docs: redesigned navigation (#9525)
Redesign navigation bar to reflect new design and allow for dropdowns Closes DX-943
This commit is contained in:
@@ -1,29 +1,55 @@
|
||||
"use client"
|
||||
|
||||
import React, { useMemo } from "react"
|
||||
import { CurrentItemsState, useSidebar } from "@/providers"
|
||||
import { TriangleRightMini } from "@medusajs/icons"
|
||||
import Link from "next/link"
|
||||
import clsx from "clsx"
|
||||
|
||||
type BreadcrumbItem = Map<string, string>
|
||||
import Link from "next/link"
|
||||
import { SidebarItemLink } from "types"
|
||||
import { CurrentItemsState, useSidebar, useSiteConfig } from "../../providers"
|
||||
import { Button } from "../Button"
|
||||
import { TriangleRightMini } from "@medusajs/icons"
|
||||
|
||||
export const Breadcrumbs = () => {
|
||||
const { currentItems } = useSidebar()
|
||||
const { currentItems, activeItem: sidebarActiveItem } = useSidebar()
|
||||
const {
|
||||
config: { breadcrumbOptions, project, baseUrl, basePath },
|
||||
} = useSiteConfig()
|
||||
|
||||
const getBreadcrumbsOfItem = (item: CurrentItemsState): BreadcrumbItem => {
|
||||
let tempBreadcrumbItems: BreadcrumbItem = new Map()
|
||||
const getLinkPath = (item?: SidebarItemLink): string | undefined => {
|
||||
if (!item) {
|
||||
return
|
||||
}
|
||||
return item.isPathHref ? item.path : `#${item.path}`
|
||||
}
|
||||
|
||||
const getBreadcrumbsOfItem = (
|
||||
item: CurrentItemsState
|
||||
): Map<string, string> => {
|
||||
let tempBreadcrumbItems: Map<string, string> = new Map()
|
||||
if (item.previousSidebar) {
|
||||
tempBreadcrumbItems = getBreadcrumbsOfItem(item.previousSidebar)
|
||||
}
|
||||
|
||||
const parentPath =
|
||||
item.parentItem?.type === "link" ? item.parentItem.path : undefined
|
||||
item.parentItem?.type === "link"
|
||||
? getLinkPath(item.parentItem)
|
||||
: (item.parentItem?.type === "category" &&
|
||||
breadcrumbOptions?.showCategories) ||
|
||||
item.parentItem?.type === "sub-category"
|
||||
? "#"
|
||||
: undefined
|
||||
const firstItemPath =
|
||||
item.default[0].type === "link" ? item.default[0].path : undefined
|
||||
item.default[0].type === "link"
|
||||
? getLinkPath(item.default[0])
|
||||
: (item.default[0].type === "category" &&
|
||||
breadcrumbOptions?.showCategories) ||
|
||||
item.default[0].type === "sub-category"
|
||||
? "#"
|
||||
: undefined
|
||||
|
||||
const breadcrumbPath = parentPath || firstItemPath || "/"
|
||||
|
||||
tempBreadcrumbItems.set(
|
||||
parentPath || firstItemPath || "/",
|
||||
breadcrumbPath,
|
||||
item.parentItem?.childSidebarTitle || item.parentItem?.title || ""
|
||||
)
|
||||
|
||||
@@ -31,51 +57,65 @@ export const Breadcrumbs = () => {
|
||||
}
|
||||
|
||||
const breadcrumbItems = useMemo(() => {
|
||||
const tempBreadcrumbItems: BreadcrumbItem = new Map()
|
||||
if (!currentItems) {
|
||||
return tempBreadcrumbItems
|
||||
const tempBreadcrumbItems: Map<string, string> = new Map()
|
||||
tempBreadcrumbItems.set(`${baseUrl}${basePath}`, project.title)
|
||||
|
||||
if (currentItems) {
|
||||
getBreadcrumbsOfItem(currentItems).forEach((value, key) =>
|
||||
tempBreadcrumbItems.set(key, value)
|
||||
)
|
||||
}
|
||||
|
||||
tempBreadcrumbItems.set("/", "Home")
|
||||
|
||||
getBreadcrumbsOfItem(currentItems).forEach((value, key) =>
|
||||
tempBreadcrumbItems.set(key, value)
|
||||
)
|
||||
if (sidebarActiveItem) {
|
||||
if (
|
||||
sidebarActiveItem.parentItem &&
|
||||
(sidebarActiveItem.parentItem.type !== "category" ||
|
||||
breadcrumbOptions?.showCategories)
|
||||
) {
|
||||
tempBreadcrumbItems.set(
|
||||
sidebarActiveItem.parentItem.type === "link"
|
||||
? getLinkPath(sidebarActiveItem.parentItem) || "#"
|
||||
: "#",
|
||||
sidebarActiveItem.parentItem.title || ""
|
||||
)
|
||||
}
|
||||
tempBreadcrumbItems.set(
|
||||
getLinkPath(sidebarActiveItem) || "/",
|
||||
sidebarActiveItem.title || ""
|
||||
)
|
||||
}
|
||||
|
||||
return tempBreadcrumbItems
|
||||
}, [currentItems])
|
||||
|
||||
const getBreadcrumbItemElms = (): React.ReactNode[] => {
|
||||
const elms: React.ReactNode[] = []
|
||||
breadcrumbItems.forEach((title, path) => {
|
||||
elms.push(
|
||||
<React.Fragment key={path}>
|
||||
{elms.length !== 0 && (
|
||||
<TriangleRightMini className={clsx("text-medusa-fg-muted")} />
|
||||
)}
|
||||
<Link
|
||||
href={path}
|
||||
className={clsx(
|
||||
"text-compact-x-small-plus text-medusa-fg-muted",
|
||||
"hover:text-medusa-fg-subtle transition-colors"
|
||||
)}
|
||||
>
|
||||
{title}
|
||||
</Link>
|
||||
</React.Fragment>
|
||||
)
|
||||
})
|
||||
|
||||
return elms
|
||||
}
|
||||
}, [currentItems, sidebarActiveItem, breadcrumbOptions])
|
||||
|
||||
return (
|
||||
<>
|
||||
{breadcrumbItems.size > 0 && (
|
||||
<div className="flex gap-docs_0.25 items-center mb-docs_1">
|
||||
{...getBreadcrumbItemElms()}
|
||||
</div>
|
||||
<div
|
||||
className={clsx(
|
||||
"flex items-center gap-docs_0.25",
|
||||
"text-medusa-fg-muted text-compact-small",
|
||||
"mb-docs_1"
|
||||
)}
|
||||
</>
|
||||
>
|
||||
{Array.from(breadcrumbItems).map(([link, title], index) => (
|
||||
<React.Fragment key={link}>
|
||||
{index > 0 && <TriangleRightMini />}
|
||||
<Button
|
||||
variant="transparent-clear"
|
||||
className={clsx(
|
||||
"px-docs_0.5 py-docs_0.25",
|
||||
link === "#" && "hover:cursor-default",
|
||||
"!p-0 hover:!bg-transparent hover:!text-medusa-fg-subtle"
|
||||
)}
|
||||
>
|
||||
<Link
|
||||
href={link}
|
||||
className={clsx(link === "#" && "hover:cursor-default")}
|
||||
>
|
||||
{title}
|
||||
</Link>
|
||||
</Button>
|
||||
</React.Fragment>
|
||||
))}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,115 +0,0 @@
|
||||
"use client"
|
||||
|
||||
import React, { useMemo } from "react"
|
||||
import { Button, CurrentItemsState, useMainNav, useSidebar } from "../../.."
|
||||
import clsx from "clsx"
|
||||
import Link from "next/link"
|
||||
import { SidebarItemLink } from "types"
|
||||
|
||||
export const MainNavBreadcrumbs = () => {
|
||||
const { currentItems, activeItem } = useSidebar()
|
||||
const {
|
||||
activeItem: mainNavActiveItem,
|
||||
breadcrumbOptions: { showCategories },
|
||||
} = useMainNav()
|
||||
|
||||
const getLinkPath = (item?: SidebarItemLink): string | undefined => {
|
||||
if (!item) {
|
||||
return
|
||||
}
|
||||
return item.isPathHref ? item.path : `#${item.path}`
|
||||
}
|
||||
|
||||
const getBreadcrumbsOfItem = (
|
||||
item: CurrentItemsState
|
||||
): Map<string, string> => {
|
||||
let tempBreadcrumbItems: Map<string, string> = new Map()
|
||||
if (item.previousSidebar) {
|
||||
tempBreadcrumbItems = getBreadcrumbsOfItem(item.previousSidebar)
|
||||
}
|
||||
|
||||
const parentPath =
|
||||
item.parentItem?.type === "link"
|
||||
? getLinkPath(item.parentItem)
|
||||
: (item.parentItem?.type === "category" && showCategories) ||
|
||||
item.parentItem?.type === "sub-category"
|
||||
? "#"
|
||||
: undefined
|
||||
const firstItemPath =
|
||||
item.default[0].type === "link"
|
||||
? getLinkPath(item.default[0])
|
||||
: (item.default[0].type === "category" && showCategories) ||
|
||||
item.default[0].type === "sub-category"
|
||||
? "#"
|
||||
: undefined
|
||||
|
||||
const breadcrumbPath = parentPath || firstItemPath || "/"
|
||||
|
||||
if (!mainNavActiveItem?.path.endsWith(breadcrumbPath)) {
|
||||
tempBreadcrumbItems.set(
|
||||
breadcrumbPath,
|
||||
item.parentItem?.childSidebarTitle || item.parentItem?.title || ""
|
||||
)
|
||||
}
|
||||
|
||||
return tempBreadcrumbItems
|
||||
}
|
||||
|
||||
const breadcrumbItems = useMemo(() => {
|
||||
const tempBreadcrumbItems: Map<string, string> = new Map()
|
||||
if (currentItems) {
|
||||
getBreadcrumbsOfItem(currentItems).forEach((value, key) =>
|
||||
tempBreadcrumbItems.set(key, value)
|
||||
)
|
||||
}
|
||||
|
||||
if (activeItem && !mainNavActiveItem?.path.endsWith(activeItem.path)) {
|
||||
if (
|
||||
activeItem.parentItem &&
|
||||
(activeItem.parentItem.type !== "category" || showCategories)
|
||||
) {
|
||||
tempBreadcrumbItems.set(
|
||||
activeItem.parentItem.type === "link"
|
||||
? getLinkPath(activeItem.parentItem) || "#"
|
||||
: "#",
|
||||
activeItem.parentItem.title || ""
|
||||
)
|
||||
}
|
||||
tempBreadcrumbItems.set(
|
||||
getLinkPath(activeItem) || "/",
|
||||
activeItem.title || ""
|
||||
)
|
||||
}
|
||||
|
||||
return tempBreadcrumbItems
|
||||
}, [currentItems, activeItem])
|
||||
|
||||
return (
|
||||
<div
|
||||
className={clsx(
|
||||
"flex items-center gap-docs_0.25",
|
||||
"text-medusa-fg-muted text-compact-small"
|
||||
)}
|
||||
>
|
||||
{Array.from(breadcrumbItems).map(([link, title]) => (
|
||||
<React.Fragment key={link}>
|
||||
<span>/</span>
|
||||
<Button
|
||||
variant="transparent-clear"
|
||||
className={clsx(
|
||||
"px-docs_0.5 py-docs_0.25",
|
||||
link === "#" && "hover:!bg-transparent hover:cursor-default"
|
||||
)}
|
||||
>
|
||||
<Link
|
||||
href={link}
|
||||
className={clsx(link === "#" && "hover:cursor-default")}
|
||||
>
|
||||
{title}
|
||||
</Link>
|
||||
</Button>
|
||||
</React.Fragment>
|
||||
))}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -1,24 +0,0 @@
|
||||
"use client"
|
||||
|
||||
import React from "react"
|
||||
import { useColorMode } from "../../../providers"
|
||||
import { Button, Tooltip } from "../../.."
|
||||
import { Moon, Sun } from "@medusajs/icons"
|
||||
import clsx from "clsx"
|
||||
|
||||
export const MainNavColorMode = () => {
|
||||
const { colorMode, toggleColorMode } = useColorMode()
|
||||
|
||||
return (
|
||||
<Tooltip place="bottom" tooltipChildren="Change Theme">
|
||||
<Button
|
||||
variant="transparent-clear"
|
||||
className={clsx("!p-[6.5px] text-medusa-fg-muted")}
|
||||
onClick={toggleColorMode}
|
||||
>
|
||||
{colorMode === "light" && <Sun />}
|
||||
{colorMode === "dark" && <Moon />}
|
||||
</Button>
|
||||
</Tooltip>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
"use client"
|
||||
|
||||
import React from "react"
|
||||
import { useColorMode } from "../../../../providers"
|
||||
import clsx from "clsx"
|
||||
import { EllipseMiniSolid } from "@medusajs/icons"
|
||||
|
||||
export const MainNavThemeMenu = () => {
|
||||
const { colorMode, setColorMode } = useColorMode()
|
||||
|
||||
return (
|
||||
<>
|
||||
<div
|
||||
className={clsx(
|
||||
"flex items-center gap-docs_0.5",
|
||||
"py-docs_0.25 px-docs_0.5",
|
||||
"rounded-docs_xs text-compact-x-small-plus",
|
||||
"text-medusa-fg-subtle"
|
||||
)}
|
||||
>
|
||||
Theme
|
||||
</div>
|
||||
<div className="px-docs_0.25">
|
||||
<div
|
||||
className={clsx(
|
||||
"flex items-center gap-docs_0.5",
|
||||
"py-docs_0.25 px-docs_0.5 cursor-pointer",
|
||||
"rounded-docs_xs text-medusa-fg-base",
|
||||
"hover:bg-medusa-bg-component-hover"
|
||||
)}
|
||||
tabIndex={-1}
|
||||
onClick={() => setColorMode("light")}
|
||||
>
|
||||
<EllipseMiniSolid
|
||||
className={clsx(colorMode !== "light" && "invisible")}
|
||||
/>
|
||||
<span
|
||||
className={clsx(
|
||||
colorMode !== "light" && "text-compact-small",
|
||||
colorMode === "light" && "text-compact-small-plus"
|
||||
)}
|
||||
>
|
||||
Light
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div className="px-docs_0.25">
|
||||
<div
|
||||
className={clsx(
|
||||
"flex items-center gap-docs_0.5",
|
||||
"py-docs_0.25 px-docs_0.5 cursor-pointer",
|
||||
"rounded-docs_xs text-medusa-fg-base",
|
||||
"hover:bg-medusa-bg-component-hover"
|
||||
)}
|
||||
tabIndex={-1}
|
||||
onClick={() => setColorMode("dark")}
|
||||
>
|
||||
<EllipseMiniSolid
|
||||
className={clsx(colorMode !== "dark" && "invisible")}
|
||||
/>
|
||||
<span
|
||||
className={clsx(
|
||||
colorMode !== "dark" && "text-compact-small",
|
||||
colorMode === "dark" && "text-compact-small-plus"
|
||||
)}
|
||||
>
|
||||
Dark
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,91 @@
|
||||
"use client"
|
||||
|
||||
import {
|
||||
BarsThree,
|
||||
QuestionMarkCircle,
|
||||
SidebarLeft,
|
||||
TimelineVertical,
|
||||
} from "@medusajs/icons"
|
||||
import React, { useRef, useState } from "react"
|
||||
import {
|
||||
Button,
|
||||
getOsShortcut,
|
||||
Menu,
|
||||
useClickOutside,
|
||||
useSidebar,
|
||||
} from "../../.."
|
||||
import clsx from "clsx"
|
||||
import { HouseIcon } from "../../Icons/House"
|
||||
import { MainNavThemeMenu } from "./ThemeMenu"
|
||||
|
||||
export const MainNavDesktopMenu = () => {
|
||||
const [isOpen, setIsOpen] = useState(false)
|
||||
const { setDesktopSidebarOpen } = useSidebar()
|
||||
const ref = useRef(null)
|
||||
|
||||
useClickOutside({
|
||||
elmRef: ref,
|
||||
onClickOutside: () => setIsOpen(false),
|
||||
})
|
||||
|
||||
return (
|
||||
<div
|
||||
className="relative hidden lg:flex justify-center items-center"
|
||||
ref={ref}
|
||||
>
|
||||
<Button
|
||||
variant="transparent"
|
||||
onClick={() => setIsOpen((prev) => !prev)}
|
||||
className="!p-[6.5px]"
|
||||
>
|
||||
<BarsThree className="text-medusa-fg-subtle" />
|
||||
</Button>
|
||||
<Menu
|
||||
className={clsx(
|
||||
"absolute top-[calc(100%+8px)] right-0 min-w-[200px]",
|
||||
!isOpen && "hidden"
|
||||
)}
|
||||
items={[
|
||||
{
|
||||
type: "link",
|
||||
icon: <HouseIcon />,
|
||||
title: "Homepage",
|
||||
link: "https://medusajs.com",
|
||||
},
|
||||
{
|
||||
type: "link",
|
||||
icon: <TimelineVertical />,
|
||||
title: "Changelog",
|
||||
link: "https://medusajs.com/changelog",
|
||||
},
|
||||
{
|
||||
type: "link",
|
||||
icon: <QuestionMarkCircle />,
|
||||
title: "Troubleshooting",
|
||||
link: "https://docs.medusajs.com/v2/resources/troubleshooting",
|
||||
},
|
||||
{
|
||||
type: "divider",
|
||||
},
|
||||
{
|
||||
type: "action",
|
||||
title: "Hide Sidebar",
|
||||
icon: <SidebarLeft />,
|
||||
shortcut: `${getOsShortcut()}\\`,
|
||||
action: () => {
|
||||
setDesktopSidebarOpen((prev) => !prev)
|
||||
setIsOpen(false)
|
||||
},
|
||||
},
|
||||
{
|
||||
type: "divider",
|
||||
},
|
||||
{
|
||||
type: "custom",
|
||||
content: <MainNavThemeMenu />,
|
||||
},
|
||||
]}
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
import clsx from "clsx"
|
||||
import React from "react"
|
||||
|
||||
export const MainNavDivider = () => {
|
||||
return (
|
||||
<span
|
||||
className={clsx("h-docs_0.75 w-px block bg-medusa-border-base")}
|
||||
></span>
|
||||
)
|
||||
}
|
||||
@@ -18,7 +18,7 @@ export const MainNavEditDate = ({ date }: MainNavEditDateProps) => {
|
||||
|
||||
return (
|
||||
<>
|
||||
<span className="text-compact-small">
|
||||
<span className="text-compact-small-plus">
|
||||
Edited {dateMatch.groups.month} {dateObj.getDate()}
|
||||
{dateObj.getFullYear() !== today.getFullYear()
|
||||
? `, ${dateObj.getFullYear()}`
|
||||
|
||||
@@ -1,76 +0,0 @@
|
||||
"use client"
|
||||
|
||||
import React, { useRef, useState } from "react"
|
||||
import { Button, Kbd, Tooltip } from "@/components"
|
||||
import { Bug, Discord, QuestionMark } from "@medusajs/icons"
|
||||
import { Menu, useClickOutside } from "../../.."
|
||||
import { MenuItem } from "types"
|
||||
import clsx from "clsx"
|
||||
import { GithubIcon } from "../../Icons/Github"
|
||||
|
||||
export const MainNavHelpButton = () => {
|
||||
const [showMenu, setShowMenu] = useState(false)
|
||||
const ref = useRef<HTMLDivElement>(null)
|
||||
useClickOutside({
|
||||
elmRef: ref,
|
||||
onClickOutside: () => {
|
||||
setShowMenu(false)
|
||||
},
|
||||
})
|
||||
|
||||
const menuItems: MenuItem[] = [
|
||||
{
|
||||
type: "link",
|
||||
title: "Create a GitHub Issue",
|
||||
link: "https://github.com/medusajs/medusa/issues/new/choose",
|
||||
icon: <GithubIcon className="text-medusa-fg-base" />,
|
||||
},
|
||||
{
|
||||
type: "link",
|
||||
title: "Get Support on Discord",
|
||||
link: "https://discord.gg/medusajs",
|
||||
icon: <Discord />,
|
||||
},
|
||||
{
|
||||
type: "divider",
|
||||
},
|
||||
{
|
||||
type: "link",
|
||||
title: "Troubleshooting Guides",
|
||||
link: "https://docs.medusajs.com/v2/resources/troubleshooting",
|
||||
icon: <Bug />,
|
||||
},
|
||||
]
|
||||
|
||||
return (
|
||||
<div className="relative" ref={ref}>
|
||||
<Tooltip
|
||||
tooltipChildren={
|
||||
<span className="flex gap-[6px] items-center">
|
||||
<span>Need help?</span>
|
||||
<Kbd className="w-docs_1 h-docs_1">?</Kbd>
|
||||
</span>
|
||||
}
|
||||
place="bottom"
|
||||
hidden={showMenu}
|
||||
>
|
||||
<Button
|
||||
variant="transparent-clear"
|
||||
className="text-medusa-fg-muted !px-[6.5px] !py-[6.5px]"
|
||||
onClick={() => setShowMenu((prev) => !prev)}
|
||||
>
|
||||
<QuestionMark />
|
||||
</Button>
|
||||
</Tooltip>
|
||||
<div
|
||||
className={clsx(
|
||||
"absolute bottom-0 left-0",
|
||||
"z-50 -translate-x-[40%] translate-y-[calc(100%+8px)]",
|
||||
!showMenu && "hidden"
|
||||
)}
|
||||
>
|
||||
<Menu items={menuItems} className="w-[200px]" />
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
"use client"
|
||||
|
||||
import { TriangleDownMini } from "@medusajs/icons"
|
||||
import clsx from "clsx"
|
||||
import React, { useRef, useState } from "react"
|
||||
import { NavigationItemDropdown } from "types"
|
||||
import { Menu, useClickOutside } from "../../../.."
|
||||
|
||||
type MainNavItemDropdownProps = {
|
||||
item: NavigationItemDropdown
|
||||
isActive: boolean
|
||||
}
|
||||
|
||||
export const MainNavItemDropdown = ({
|
||||
item,
|
||||
isActive,
|
||||
}: MainNavItemDropdownProps) => {
|
||||
const [isOpen, setIsOpen] = useState(false)
|
||||
const ref = useRef(null)
|
||||
|
||||
useClickOutside({
|
||||
elmRef: ref,
|
||||
onClickOutside: () => setIsOpen(false),
|
||||
})
|
||||
|
||||
return (
|
||||
<div className={clsx("relative")} ref={ref}>
|
||||
<div
|
||||
className={clsx(
|
||||
"cursor-pointer flex gap-docs_0.25 items-center",
|
||||
isActive && "text-medusa-fg-base",
|
||||
!isActive && [
|
||||
"text-medusa-fg-muted hover:text-medusa-fg-subtle",
|
||||
isOpen && "text-medusa-fg-subtle",
|
||||
]
|
||||
)}
|
||||
tabIndex={-1}
|
||||
onClick={() => setIsOpen((prev) => !prev)}
|
||||
>
|
||||
<span className="text-compact-small-plus">{item.title}</span>
|
||||
<TriangleDownMini
|
||||
className={clsx("transition-transform", isOpen && "rotate-180")}
|
||||
/>
|
||||
</div>
|
||||
<Menu
|
||||
className={clsx(
|
||||
"absolute top-[calc(100%+4px)] -left-docs_0.75 min-w-[190px]",
|
||||
!isOpen && "hidden"
|
||||
)}
|
||||
items={item.children}
|
||||
itemsOnClick={() => setIsOpen(false)}
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
"use client"
|
||||
|
||||
import React from "react"
|
||||
import { NavigationItemLink } from "types"
|
||||
import { LinkButton } from "../../../.."
|
||||
import clsx from "clsx"
|
||||
|
||||
type MainNavItemLinkProps = {
|
||||
item: NavigationItemLink
|
||||
isActive: boolean
|
||||
}
|
||||
|
||||
export const MainNavItemLink = ({ item, isActive }: MainNavItemLinkProps) => {
|
||||
return (
|
||||
<LinkButton
|
||||
href={item.path}
|
||||
className={clsx(
|
||||
isActive && "text-medusa-fg-base",
|
||||
!isActive && "text-medusa-fg-muted hover:text-medusa-fg-subtle"
|
||||
)}
|
||||
>
|
||||
{item.title}
|
||||
</LinkButton>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
"use client"
|
||||
|
||||
import React from "react"
|
||||
import { useMainNav } from "../../.."
|
||||
import clsx from "clsx"
|
||||
import { MainNavItemLink } from "./Link"
|
||||
import { MainNavItemDropdown } from "./Dropdown"
|
||||
|
||||
export const MainNavItems = () => {
|
||||
const { navItems, activeItemIndex } = useMainNav()
|
||||
|
||||
return (
|
||||
<ul
|
||||
className={clsx(
|
||||
"hidden lg:flex justify-start gap-docs_1 items-center",
|
||||
"my-docs_0.75"
|
||||
)}
|
||||
>
|
||||
{navItems.map((item, index) => {
|
||||
const isActive = index === activeItemIndex
|
||||
|
||||
return (
|
||||
<li className={clsx("flex items-center group")} key={index}>
|
||||
{item.type === "link" && (
|
||||
<MainNavItemLink item={item} isActive={isActive} />
|
||||
)}
|
||||
{item.type === "dropdown" && (
|
||||
<MainNavItemDropdown item={item} isActive={isActive} />
|
||||
)}
|
||||
</li>
|
||||
)
|
||||
})}
|
||||
</ul>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
"use client"
|
||||
|
||||
import React from "react"
|
||||
import { useMainNav } from "../../../../providers"
|
||||
import Link from "next/link"
|
||||
import { TriangleRightMini } from "@medusajs/icons"
|
||||
import clsx from "clsx"
|
||||
import { SelectedMenu } from ".."
|
||||
|
||||
type MainNavMobileMainMenu = {
|
||||
setSelectedMenu: (menu: SelectedMenu) => void
|
||||
}
|
||||
|
||||
export const MainNavMobileMainMenu = ({
|
||||
setSelectedMenu,
|
||||
}: MainNavMobileMainMenu) => {
|
||||
const { navItems } = useMainNav()
|
||||
|
||||
return (
|
||||
<div className="flex flex-col gap-[23px]">
|
||||
<span className="text-compact-small-plus text-medusa-fg-muted uppercase">
|
||||
Menu
|
||||
</span>
|
||||
<ul className="flex flex-col gap-[18px]">
|
||||
{navItems.map((item, index) => (
|
||||
<li
|
||||
key={index}
|
||||
className={clsx(
|
||||
"text-h1 text-medusa-fg-base cursor-pointer",
|
||||
"flex justify-between gap-docs_1"
|
||||
)}
|
||||
onClick={() => {
|
||||
if (item.type !== "dropdown") {
|
||||
return
|
||||
}
|
||||
|
||||
setSelectedMenu({
|
||||
title: item.title,
|
||||
menu: item.children,
|
||||
})
|
||||
}}
|
||||
>
|
||||
{item.type === "link" && (
|
||||
<Link href={item.path} className="block w-full">
|
||||
{item.title}
|
||||
</Link>
|
||||
)}
|
||||
{item.type === "dropdown" && (
|
||||
<>
|
||||
<span>{item.title}</span>
|
||||
<TriangleRightMini />
|
||||
</>
|
||||
)}
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
"use client"
|
||||
|
||||
import clsx from "clsx"
|
||||
import Link from "next/link"
|
||||
import React, { useMemo } from "react"
|
||||
import { MenuItem, MenuItemLink } from "types"
|
||||
|
||||
type MainNavMobileSubMenuProps = {
|
||||
menu: MenuItem[]
|
||||
title: string
|
||||
}
|
||||
|
||||
export const MainNavMobileSubMenu = ({
|
||||
menu,
|
||||
title,
|
||||
}: MainNavMobileSubMenuProps) => {
|
||||
const filteredItems: MenuItemLink[] = useMemo(() => {
|
||||
return menu.filter((item) => item.type === "link") as MenuItemLink[]
|
||||
}, [menu])
|
||||
return (
|
||||
<div className="flex flex-col gap-[23px]">
|
||||
<span className="text-compact-small-plus text-medusa-fg-muted uppercase">
|
||||
{title}
|
||||
</span>
|
||||
<ul className="flex flex-col gap-[18px]">
|
||||
{filteredItems.map((item, index) => (
|
||||
<li
|
||||
key={index}
|
||||
className={clsx(
|
||||
"text-h1 text-medusa-fg-base cursor-pointer",
|
||||
"flex justify-between gap-docs_1"
|
||||
)}
|
||||
>
|
||||
<Link href={item.link} className="block w-full">
|
||||
{item.title}
|
||||
</Link>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
"use client"
|
||||
|
||||
import React, { useRef, useState } from "react"
|
||||
import { Button } from "../../Button"
|
||||
import { ArrowUturnLeft, BarsThree, XMark } from "@medusajs/icons"
|
||||
import clsx from "clsx"
|
||||
import { MenuItem } from "types"
|
||||
import { CSSTransition, SwitchTransition } from "react-transition-group"
|
||||
import { MainNavMobileMainMenu } from "./Main"
|
||||
import { MainNavMobileSubMenu } from "./SubMenu"
|
||||
|
||||
export type SelectedMenu = {
|
||||
title: string
|
||||
menu: MenuItem[]
|
||||
}
|
||||
|
||||
export const MainNavMobileMenu = () => {
|
||||
const [isOpen, setIsOpen] = useState(false)
|
||||
const [selectedMenu, setSelectedMenu] = useState<SelectedMenu>()
|
||||
const ref = useRef(null)
|
||||
|
||||
return (
|
||||
<div className="flex lg:hidden justify-center items-center">
|
||||
<Button
|
||||
variant="transparent"
|
||||
onClick={() => setIsOpen((prev) => !prev)}
|
||||
className="text-medusa-fg-subtle !p-[6.5px]"
|
||||
>
|
||||
{!isOpen && <BarsThree />}
|
||||
{isOpen && <XMark />}
|
||||
</Button>
|
||||
<div
|
||||
className={clsx(
|
||||
"flex items-center justify-center fixed w-full h-[calc(100vh-52px)]",
|
||||
"top-[52px] transition-[left] bg-medusa-bg-subtle z-50",
|
||||
!isOpen && "-left-full",
|
||||
isOpen && "left-0"
|
||||
)}
|
||||
>
|
||||
<SwitchTransition>
|
||||
<CSSTransition
|
||||
key={!selectedMenu ? "main" : "sub"}
|
||||
classNames={{
|
||||
enter: "animate-fadeInLeft animate-fast",
|
||||
exit: "animate-fadeOutRight animate-fast",
|
||||
}}
|
||||
nodeRef={ref}
|
||||
timeout={250}
|
||||
>
|
||||
<div ref={ref} className="w-full px-docs_1.5">
|
||||
{!selectedMenu && (
|
||||
<MainNavMobileMainMenu setSelectedMenu={setSelectedMenu} />
|
||||
)}
|
||||
{selectedMenu && (
|
||||
<>
|
||||
<div
|
||||
className={clsx(
|
||||
"flex items-center gap-docs_0.5",
|
||||
"text-medusa-fg-base my-[14px]",
|
||||
"cursor-pointer"
|
||||
)}
|
||||
tabIndex={-1}
|
||||
onClick={() => setSelectedMenu(undefined)}
|
||||
>
|
||||
<ArrowUturnLeft />
|
||||
<span className="text-h1">Back</span>
|
||||
</div>
|
||||
<MainNavMobileSubMenu {...selectedMenu} />
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
</CSSTransition>
|
||||
</SwitchTransition>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -1,21 +0,0 @@
|
||||
import React from "react"
|
||||
import { BorderedIcon } from "@/components"
|
||||
import { IconProps } from "@medusajs/icons/dist/types"
|
||||
|
||||
export type MainNavigationDropdownIconProps = {
|
||||
icon: React.FC<IconProps>
|
||||
inDropdown?: boolean
|
||||
}
|
||||
|
||||
export const MainNavigationDropdownIcon = ({
|
||||
icon,
|
||||
inDropdown = false,
|
||||
}: MainNavigationDropdownIconProps) => {
|
||||
return (
|
||||
<BorderedIcon
|
||||
IconComponent={icon}
|
||||
iconClassName={inDropdown ? "w-docs_1 h-docs_1" : ""}
|
||||
iconWrapperClassName="rounded-docs_xs"
|
||||
/>
|
||||
)
|
||||
}
|
||||
@@ -1,50 +0,0 @@
|
||||
"use client"
|
||||
|
||||
import React from "react"
|
||||
import { NavigationDropdownItem } from "types"
|
||||
import Link from "next/link"
|
||||
import clsx from "clsx"
|
||||
import { EllipseMiniSolid } from "@medusajs/icons"
|
||||
import { MainNavigationDropdownIcon } from "../../Icon"
|
||||
import { DottedSeparator } from "../../../.."
|
||||
|
||||
export type MainNavigationDropdownMenuItemProps = {
|
||||
item: NavigationDropdownItem
|
||||
onSelect: () => void
|
||||
}
|
||||
|
||||
export const MainNavigationDropdownMenuItem = ({
|
||||
item,
|
||||
onSelect,
|
||||
}: MainNavigationDropdownMenuItemProps) => {
|
||||
switch (item.type) {
|
||||
case "divider":
|
||||
return <DottedSeparator className="my-docs_0.25" />
|
||||
case "link":
|
||||
return (
|
||||
<Link
|
||||
href={item.path}
|
||||
className={clsx(
|
||||
"hover:bg-medusa-bg-component-hover",
|
||||
"block rounded-docs_xs"
|
||||
)}
|
||||
prefetch={false}
|
||||
onClick={onSelect}
|
||||
>
|
||||
<li
|
||||
className={clsx(
|
||||
"px-docs_0.5 py-docs_0.25",
|
||||
"rounded-docs_xs text-medusa-fg-base",
|
||||
"flex gap-docs_0.5 justify-start items-center"
|
||||
)}
|
||||
>
|
||||
<span className={clsx(!item.isActive && "invisible")}>
|
||||
<EllipseMiniSolid />
|
||||
</span>
|
||||
<MainNavigationDropdownIcon icon={item.icon} inDropdown={true} />
|
||||
<span className="whitespace-nowrap">{item.title}</span>
|
||||
</li>
|
||||
</Link>
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -1,36 +0,0 @@
|
||||
"use client"
|
||||
|
||||
import clsx from "clsx"
|
||||
import React from "react"
|
||||
import { NavigationDropdownItem } from "types"
|
||||
import { MainNavigationDropdownMenuItem } from "./Item"
|
||||
|
||||
export type MainNavigationDropdownMenuProps = {
|
||||
items: NavigationDropdownItem[]
|
||||
open: boolean
|
||||
onSelect: () => void
|
||||
}
|
||||
|
||||
export const MainNavigationDropdownMenu = ({
|
||||
items,
|
||||
open,
|
||||
onSelect,
|
||||
}: MainNavigationDropdownMenuProps) => {
|
||||
return (
|
||||
<ul
|
||||
className={clsx(
|
||||
"absolute top-[calc(100%+4px)] p-docs_0.25 z-50 lg:-left-docs_0.25",
|
||||
"bg-medusa-bg-component rounded shadow-elevation-flyout",
|
||||
!open && "hidden"
|
||||
)}
|
||||
>
|
||||
{items.map((item, index) => (
|
||||
<MainNavigationDropdownMenuItem
|
||||
item={item}
|
||||
key={index}
|
||||
onSelect={onSelect}
|
||||
/>
|
||||
))}
|
||||
</ul>
|
||||
)
|
||||
}
|
||||
@@ -1,49 +0,0 @@
|
||||
"use client"
|
||||
|
||||
import React from "react"
|
||||
import { NavigationDropdownItem } from "types"
|
||||
import { TrianglesMini } from "@medusajs/icons"
|
||||
import clsx from "clsx"
|
||||
import { MainNavigationDropdownIcon } from "../Icon"
|
||||
|
||||
export type MainNavigationDropdownSelectedProps = {
|
||||
item: NavigationDropdownItem
|
||||
onClick: () => void
|
||||
isActive: boolean
|
||||
}
|
||||
|
||||
export const MainNavigationDropdownSelected = ({
|
||||
item,
|
||||
onClick,
|
||||
isActive,
|
||||
}: MainNavigationDropdownSelectedProps) => {
|
||||
if (item.type === "divider") {
|
||||
return <></>
|
||||
}
|
||||
|
||||
return (
|
||||
<div
|
||||
className={clsx(
|
||||
"flex justify-between items-center gap-docs_0.25",
|
||||
"cursor-pointer rounded-docs_sm group"
|
||||
)}
|
||||
tabIndex={-1}
|
||||
onClick={onClick}
|
||||
>
|
||||
<MainNavigationDropdownIcon icon={item.icon} />
|
||||
<div
|
||||
className={clsx(
|
||||
"flex gap-[6px] py-docs_0.25 px-docs_0.5",
|
||||
"items-center group-hover:bg-medusa-button-transparent-hover",
|
||||
"rounded-docs_sm",
|
||||
isActive && "bg-medusa-button-transparent-hover"
|
||||
)}
|
||||
>
|
||||
<span className="text-medusa-fg-base whitespace-nowrap flex-1 text-compact-small-plus">
|
||||
{item.title}
|
||||
</span>
|
||||
<TrianglesMini className="text-medusa-fg-muted" />
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -1,55 +0,0 @@
|
||||
"use client"
|
||||
|
||||
import clsx from "clsx"
|
||||
import React, { useMemo, useRef, useState } from "react"
|
||||
import { MainNavigationDropdownSelected } from "./Selected"
|
||||
import { MainNavigationDropdownMenu } from "./Menu"
|
||||
import { useAnalytics, useClickOutside, useMainNav } from "../../.."
|
||||
|
||||
export const MainNavigationDropdown = () => {
|
||||
const { navItems: items } = useMainNav()
|
||||
const navigationRef = useRef<HTMLDivElement>(null)
|
||||
const [menuOpen, setMenuOpen] = useState(false)
|
||||
const { track } = useAnalytics()
|
||||
useClickOutside({
|
||||
elmRef: navigationRef,
|
||||
onClickOutside: () => {
|
||||
setMenuOpen(false)
|
||||
},
|
||||
})
|
||||
|
||||
const selectedItem = useMemo(() => {
|
||||
const activeItem = items.find(
|
||||
(item) => item.type === "link" && item.isActive
|
||||
)
|
||||
|
||||
if (!activeItem) {
|
||||
return items.length ? items[0] : undefined
|
||||
}
|
||||
|
||||
return activeItem
|
||||
}, [items])
|
||||
return (
|
||||
<div className={clsx("relative z-50")} ref={navigationRef}>
|
||||
{selectedItem && (
|
||||
<MainNavigationDropdownSelected
|
||||
item={selectedItem}
|
||||
onClick={() => {
|
||||
setMenuOpen((prev) => !prev)
|
||||
if (!menuOpen) {
|
||||
track("nav_main_open", {
|
||||
url: window.location.href,
|
||||
})
|
||||
}
|
||||
}}
|
||||
isActive={menuOpen}
|
||||
/>
|
||||
)}
|
||||
<MainNavigationDropdownMenu
|
||||
items={items}
|
||||
open={menuOpen}
|
||||
onSelect={() => setMenuOpen(false)}
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -1,24 +0,0 @@
|
||||
"use client"
|
||||
|
||||
import React from "react"
|
||||
import { Button, useSidebar } from "../../.."
|
||||
import clsx from "clsx"
|
||||
import { SidebarLeft } from "@medusajs/icons"
|
||||
|
||||
export const MainNavSidebarOpener = () => {
|
||||
const { desktopSidebarOpen, setDesktopSidebarOpen } = useSidebar()
|
||||
|
||||
if (desktopSidebarOpen) {
|
||||
return <></>
|
||||
}
|
||||
|
||||
return (
|
||||
<Button
|
||||
variant="transparent-clear"
|
||||
className={clsx("!p-[6.5px] text-medusa-fg-muted", "mr-docs_0.5")}
|
||||
onClick={() => setDesktopSidebarOpen(true)}
|
||||
>
|
||||
<SidebarLeft />
|
||||
</Button>
|
||||
)
|
||||
}
|
||||
@@ -2,57 +2,65 @@
|
||||
|
||||
import clsx from "clsx"
|
||||
import React from "react"
|
||||
import { MainNavigationDropdown } from "./NavigationDropdown"
|
||||
import { MainNavBreadcrumbs } from "./Breadcrumb"
|
||||
import {
|
||||
BorderedIcon,
|
||||
Button,
|
||||
LinkButton,
|
||||
SearchModalOpener,
|
||||
useMainNav,
|
||||
useSidebar,
|
||||
} from "../.."
|
||||
import { MainNavColorMode } from "./ColorMode"
|
||||
import { MainNavDivider } from "./Divider"
|
||||
import { MainNavSidebarOpener } from "./SidebarOpener"
|
||||
import { MainNavHelpButton } from "./HelpButton"
|
||||
import { SidebarLeftIcon } from "../Icons/SidebarLeft"
|
||||
import { MainNavEditDate } from "./EditDate"
|
||||
import { MainNavItems } from "./Items"
|
||||
import { MedusaIcon } from "../Icons/MedusaLogo"
|
||||
import { MainNavDesktopMenu } from "./DesktopMenu"
|
||||
import { SidebarLeftIcon } from "../Icons/SidebarLeft"
|
||||
import { MainNavMobileMenu } from "./MobileMenu"
|
||||
|
||||
export const MainNav = () => {
|
||||
const { reportIssueLink, editDate } = useMainNav()
|
||||
const { setMobileSidebarOpen } = useSidebar()
|
||||
|
||||
return (
|
||||
<div
|
||||
className={clsx(
|
||||
"hidden sm:flex justify-between items-center",
|
||||
"px-docs_1 py-docs_0.75 w-full z-20",
|
||||
"flex justify-between items-center",
|
||||
"px-docs_1 w-full z-20",
|
||||
"sticky top-0 bg-medusa-bg-base"
|
||||
)}
|
||||
>
|
||||
<div className="flex items-center gap-docs_0.25">
|
||||
<Button
|
||||
className="lg:hidden"
|
||||
variant="transparent-clear"
|
||||
onClick={() => setMobileSidebarOpen(true)}
|
||||
>
|
||||
<SidebarLeftIcon />
|
||||
</Button>
|
||||
<MainNavSidebarOpener />
|
||||
<MainNavigationDropdown />
|
||||
<MainNavBreadcrumbs />
|
||||
<div className="flex items-center gap-docs_1">
|
||||
<div className="flex items-center gap-[10px]">
|
||||
<Button
|
||||
className="lg:hidden my-docs_0.75 !p-[6.5px]"
|
||||
variant="transparent-clear"
|
||||
onClick={() => setMobileSidebarOpen(true)}
|
||||
>
|
||||
<SidebarLeftIcon />
|
||||
</Button>
|
||||
<BorderedIcon
|
||||
IconComponent={MedusaIcon}
|
||||
iconWrapperClassName="my-[14px]"
|
||||
/>
|
||||
</div>
|
||||
<MainNavItems />
|
||||
</div>
|
||||
<div className="flex items-center gap-docs_0.75">
|
||||
<div className="flex items-center gap-[6px] text-medusa-fg-muted">
|
||||
<div className="flex items-center gap-docs_0.75 my-docs_0.75">
|
||||
<div className="lg:flex items-center gap-docs_0.5 text-medusa-fg-subtle hidden">
|
||||
{editDate && <MainNavEditDate date={editDate} />}
|
||||
<LinkButton href={reportIssueLink} variant="muted" target="_blank">
|
||||
<LinkButton
|
||||
href={reportIssueLink}
|
||||
variant="subtle"
|
||||
target="_blank"
|
||||
className="text-compact-small-plus"
|
||||
>
|
||||
Report Issue
|
||||
</LinkButton>
|
||||
</div>
|
||||
<MainNavDivider />
|
||||
<div className="flex items-center gap-docs_0.25">
|
||||
<MainNavHelpButton />
|
||||
<MainNavColorMode />
|
||||
<SearchModalOpener />
|
||||
<MainNavDesktopMenu />
|
||||
<MainNavMobileMenu />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -2,13 +2,14 @@
|
||||
|
||||
import clsx from "clsx"
|
||||
import React from "react"
|
||||
import { MenuItemAction } from "types"
|
||||
import { MenuItem, MenuItemAction } from "types"
|
||||
|
||||
export type MenuActionProps = {
|
||||
item: MenuItemAction
|
||||
onClick?: (item: MenuItem) => void
|
||||
}
|
||||
|
||||
export const MenuAction = ({ item }: MenuActionProps) => {
|
||||
export const MenuAction = ({ item, onClick }: MenuActionProps) => {
|
||||
return (
|
||||
<div className="px-docs_0.25">
|
||||
<span
|
||||
@@ -19,7 +20,10 @@ export const MenuAction = ({ item }: MenuActionProps) => {
|
||||
"text-medusa-fg-base cursor-pointer"
|
||||
)}
|
||||
tabIndex={-1}
|
||||
onClick={item.action}
|
||||
onClick={() => {
|
||||
item.action()
|
||||
onClick?.(item)
|
||||
}}
|
||||
>
|
||||
<span className="text-medusa-fg-subtle mt-[2.5px] block">
|
||||
{item.icon}
|
||||
|
||||
@@ -3,13 +3,14 @@
|
||||
import clsx from "clsx"
|
||||
import Link from "next/link"
|
||||
import React from "react"
|
||||
import { MenuItemLink } from "types"
|
||||
import { MenuItem as MenuItemType, MenuItemLink } from "types"
|
||||
|
||||
export type MenuItemProps = {
|
||||
item: MenuItemLink
|
||||
onClick?: (item: MenuItemType) => void
|
||||
}
|
||||
|
||||
export const MenuItem = ({ item }: MenuItemProps) => {
|
||||
export const MenuItem = ({ item, onClick }: MenuItemProps) => {
|
||||
return (
|
||||
<div className="px-docs_0.25">
|
||||
<Link
|
||||
@@ -20,10 +21,13 @@ export const MenuItem = ({ item }: MenuItemProps) => {
|
||||
"text-medusa-fg-base"
|
||||
)}
|
||||
href={item.link}
|
||||
onClick={() => onClick?.(item)}
|
||||
>
|
||||
<span className="text-medusa-fg-subtle mt-[2.5px] block">
|
||||
{item.icon}
|
||||
</span>
|
||||
{item.icon && (
|
||||
<span className="text-medusa-fg-subtle mt-[2.5px] block">
|
||||
{item.icon}
|
||||
</span>
|
||||
)}
|
||||
<span className="text-compact-small">{item.title}</span>
|
||||
</Link>
|
||||
</div>
|
||||
|
||||
@@ -8,9 +8,10 @@ import { MenuAction } from "./Action"
|
||||
export type MenuProps = {
|
||||
items: MenuItemType[]
|
||||
className?: string
|
||||
itemsOnClick?: (item: MenuItemType) => void
|
||||
}
|
||||
|
||||
export const Menu = ({ items, className }: MenuProps) => {
|
||||
export const Menu = ({ items, className, itemsOnClick }: MenuProps) => {
|
||||
return (
|
||||
<div
|
||||
className={clsx(
|
||||
@@ -21,9 +22,14 @@ export const Menu = ({ items, className }: MenuProps) => {
|
||||
>
|
||||
{items.map((item, index) => (
|
||||
<React.Fragment key={index}>
|
||||
{item.type === "link" && <MenuItem item={item} />}
|
||||
{item.type === "action" && <MenuAction item={item} />}
|
||||
{item.type === "link" && (
|
||||
<MenuItem item={item} onClick={itemsOnClick} />
|
||||
)}
|
||||
{item.type === "action" && (
|
||||
<MenuAction item={item} onClick={itemsOnClick} />
|
||||
)}
|
||||
{item.type === "divider" && <MenuDivider />}
|
||||
{item.type === "custom" && item.content}
|
||||
</React.Fragment>
|
||||
))}
|
||||
</div>
|
||||
|
||||
@@ -1,32 +0,0 @@
|
||||
"use client"
|
||||
|
||||
import clsx from "clsx"
|
||||
import React from "react"
|
||||
import { SidebarLeftIcon } from "../Icons/SidebarLeft"
|
||||
import { Button, SearchModalOpener, useSidebar } from "../.."
|
||||
import { MainNavigationDropdown } from "../MainNav/NavigationDropdown"
|
||||
|
||||
export const MobileNavigation = () => {
|
||||
const { setMobileSidebarOpen } = useSidebar()
|
||||
|
||||
return (
|
||||
<div
|
||||
className={clsx(
|
||||
"sm:hidden bg-medusa-bg-base",
|
||||
"sticky top-0 w-full z-40 h-min",
|
||||
"px-docs_0.75 py-docs_0.5",
|
||||
"flex justify-between items-center",
|
||||
"border-b border-medusa-border-base"
|
||||
)}
|
||||
>
|
||||
<Button
|
||||
variant="transparent-clear"
|
||||
onClick={() => setMobileSidebarOpen(true)}
|
||||
>
|
||||
<SidebarLeftIcon />
|
||||
</Button>
|
||||
<MainNavigationDropdown />
|
||||
<SearchModalOpener />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -1,9 +1,8 @@
|
||||
"use client"
|
||||
|
||||
import React, { MouseEvent, useMemo } from "react"
|
||||
import clsx from "clsx"
|
||||
import { useMobile, useSearch } from "@/providers"
|
||||
import { Button, Tooltip } from "@/components"
|
||||
import React, { MouseEvent } from "react"
|
||||
import { useSearch } from "@/providers"
|
||||
import { Button } from "@/components"
|
||||
import { MagnifyingGlass } from "@medusajs/icons"
|
||||
import { useKeyboardShortcut } from "@/hooks"
|
||||
|
||||
@@ -14,15 +13,8 @@ export type SearchModalOpenerProps = {
|
||||
|
||||
export const SearchModalOpener = ({
|
||||
isLoading = false,
|
||||
className,
|
||||
}: SearchModalOpenerProps) => {
|
||||
const { isMobile } = useMobile()
|
||||
const { setIsOpen } = useSearch()
|
||||
const isApple = useMemo(() => {
|
||||
return typeof navigator !== "undefined"
|
||||
? navigator.userAgent.toLowerCase().indexOf("mac") !== 0
|
||||
: true
|
||||
}, [])
|
||||
useKeyboardShortcut({
|
||||
shortcutKeys: ["k"],
|
||||
action: () => setIsOpen((prev) => !prev),
|
||||
@@ -46,29 +38,12 @@ export const SearchModalOpener = ({
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
{isMobile && (
|
||||
<Button variant="transparent" onClick={handleOpen}>
|
||||
<MagnifyingGlass className="text-medusa-fg-muted" />
|
||||
</Button>
|
||||
)}
|
||||
{!isMobile && (
|
||||
<Tooltip place="bottom" tooltipChildren="Ask or search">
|
||||
<Button
|
||||
className={clsx(
|
||||
"relative hover:cursor-pointer group",
|
||||
"flex gap-[6px] !py-docs_0.25 !px-docs_0.5",
|
||||
"justify-between items-center text-medusa-fg-muted",
|
||||
className
|
||||
)}
|
||||
variant="transparent-clear"
|
||||
onClick={handleOpen}
|
||||
>
|
||||
<MagnifyingGlass />
|
||||
<span>{isApple ? "⌘" : "Ctrl"}K</span>
|
||||
</Button>
|
||||
</Tooltip>
|
||||
)}
|
||||
</>
|
||||
<Button
|
||||
variant="transparent"
|
||||
onClick={handleOpen}
|
||||
className="hidden sm:flex !p-[6.5px]"
|
||||
>
|
||||
<MagnifyingGlass className="text-medusa-fg-subtle" />
|
||||
</Button>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -4,7 +4,6 @@ import React from "react"
|
||||
import { SidebarChild } from "../Child"
|
||||
import { InteractiveSidebarItem } from "types"
|
||||
import { SidebarTopMobileClose } from "./MobileClose"
|
||||
import { SidebarTopMedusaMenu } from "./MedusaMenu"
|
||||
import { DottedSeparator } from "../../.."
|
||||
|
||||
export type SidebarTopProps = {
|
||||
@@ -17,14 +16,12 @@ export const SidebarTop = React.forwardRef<HTMLDivElement, SidebarTopProps>(
|
||||
<div className="pt-docs_0.25">
|
||||
<SidebarTopMobileClose />
|
||||
<div ref={ref}>
|
||||
<SidebarTopMedusaMenu />
|
||||
{parentItem && (
|
||||
<>
|
||||
<DottedSeparator />
|
||||
<SidebarChild item={parentItem} />
|
||||
<DottedSeparator wrapperClassName="!my-0" />
|
||||
</>
|
||||
)}
|
||||
<DottedSeparator wrapperClassName="!my-0" />
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
|
||||
@@ -118,8 +118,8 @@ export const Sidebar = ({
|
||||
}}
|
||||
id="sidebar"
|
||||
>
|
||||
{/* MOBILE SIDEBAR */}
|
||||
<div className={clsx("lg:hidden")}>
|
||||
{/* MOBILE SIDEBAR - keeping this in case we need it in the future */}
|
||||
{/* <div className={clsx("lg:hidden")}>
|
||||
{!sidebarItems.mobile.length && !staticSidebarItems && (
|
||||
<Loading className="px-0" />
|
||||
)}
|
||||
@@ -131,8 +131,8 @@ export const Sidebar = ({
|
||||
hasNextItems={index !== sidebarItems.default.length - 1}
|
||||
/>
|
||||
))}
|
||||
<DottedSeparator />
|
||||
</div>
|
||||
{sidebarItems.mobile.length > 0 && <DottedSeparator />}
|
||||
</div> */}
|
||||
{/* DESKTOP SIDEBAR */}
|
||||
<div className="mt-docs_0.75 lg:mt-0">
|
||||
{!sidebarItems.default.length && !staticSidebarItems && (
|
||||
|
||||
@@ -1,195 +1,118 @@
|
||||
import React from "react"
|
||||
import { Badge } from "@/components"
|
||||
import { OptionType } from "@/hooks"
|
||||
import { NavigationDropdownItem, SidebarItem } from "types"
|
||||
import { NavigationDropdownDocIcon } from "./components/Icons/NavigationDropdown/Doc"
|
||||
import { NavigationDropdownStoreIcon } from "./components/Icons/NavigationDropdown/Store"
|
||||
import { NavigationDropdownAdminIcon } from "./components/Icons/NavigationDropdown/Admin"
|
||||
import { NavigationDropdownUiIcon } from "./components/Icons/NavigationDropdown/Ui"
|
||||
import { NavigationDropdownDocV1Icon } from "./components/Icons/NavigationDropdown/DocV1"
|
||||
import { NavigationDropdownUserIcon } from "./components/Icons/NavigationDropdown/User"
|
||||
import { NavigationDropdownResourcesIcon } from "./components/Icons/NavigationDropdown/Resources"
|
||||
import { NavigationDropdownModulesIcon } from "./components/Icons/NavigationDropdown/Modules"
|
||||
import { NavigationItem } from "types"
|
||||
|
||||
export const GITHUB_ISSUES_PREFIX = `https://github.com/medusajs/medusa/issues/new?assignees=&labels=type%3A+docs&template=docs.yml`
|
||||
export const GITHUB_UI_ISSUES_PREFIX = `https://github.com/medusajs/ui/issues/new?labels=documentation`
|
||||
|
||||
export const navDropdownItemsV2: NavigationDropdownItem[] = [
|
||||
export const navDropdownItems: NavigationItem[] = [
|
||||
{
|
||||
type: "link",
|
||||
path: `/v2`,
|
||||
icon: NavigationDropdownDocIcon,
|
||||
title: "Documentation",
|
||||
title: "Get Started",
|
||||
project: "book",
|
||||
},
|
||||
{
|
||||
type: "link",
|
||||
path: `/v2/resources/commerce-modules`,
|
||||
icon: NavigationDropdownModulesIcon,
|
||||
title: "Commerce Modules",
|
||||
type: "dropdown",
|
||||
title: "Product",
|
||||
children: [
|
||||
{
|
||||
type: "link",
|
||||
title: "Commerce Modules",
|
||||
link: "/v2/resources/commerce-modules",
|
||||
},
|
||||
{
|
||||
type: "link",
|
||||
title: "Architectural Modules",
|
||||
link: "/v2/resources/architectural-modules",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
type: "link",
|
||||
path: `/v2/resources`,
|
||||
icon: NavigationDropdownResourcesIcon,
|
||||
title: "Development Resources",
|
||||
type: "dropdown",
|
||||
title: "Resources",
|
||||
children: [
|
||||
{
|
||||
type: "link",
|
||||
title: "Guides",
|
||||
link: "/v2/resources",
|
||||
useAsFallback: true,
|
||||
},
|
||||
{
|
||||
type: "link",
|
||||
title: "Recipes",
|
||||
link: "/v2/resources/recipes",
|
||||
},
|
||||
{
|
||||
type: "link",
|
||||
title: "UI Library",
|
||||
link: "/ui",
|
||||
},
|
||||
{
|
||||
type: "divider",
|
||||
},
|
||||
{
|
||||
type: "link",
|
||||
title: "Storefront Development",
|
||||
link: "/v2/resources/storefront-development",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
type: "link",
|
||||
path: `/v2/api/store`,
|
||||
icon: NavigationDropdownStoreIcon,
|
||||
title: "Store API",
|
||||
type: "dropdown",
|
||||
title: "Tools & SDKs",
|
||||
children: [
|
||||
{
|
||||
type: "link",
|
||||
title: "Medusa CLI",
|
||||
link: "/v2/resources/medusa-cli",
|
||||
},
|
||||
{
|
||||
type: "link",
|
||||
title: "Next.js Starter",
|
||||
link: "/v2/resources/nextjs-starter",
|
||||
},
|
||||
{
|
||||
type: "divider",
|
||||
},
|
||||
{
|
||||
type: "link",
|
||||
title: "Integrations",
|
||||
link: "/v2/resources/integrations",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
type: "link",
|
||||
path: `/v2/api/admin`,
|
||||
icon: NavigationDropdownAdminIcon,
|
||||
title: "Admin API",
|
||||
},
|
||||
{
|
||||
type: "link",
|
||||
path: `/ui`,
|
||||
icon: NavigationDropdownUiIcon,
|
||||
title: "UI",
|
||||
},
|
||||
{
|
||||
type: "link",
|
||||
path: `/`,
|
||||
icon: NavigationDropdownDocV1Icon,
|
||||
title: "Medusa v1",
|
||||
type: "dropdown",
|
||||
title: "Reference",
|
||||
children: [
|
||||
{
|
||||
type: "link",
|
||||
title: "Admin API",
|
||||
link: "/v2/api/admin",
|
||||
},
|
||||
{
|
||||
type: "link",
|
||||
title: "Store API",
|
||||
link: "/v2/api/store",
|
||||
},
|
||||
{
|
||||
type: "divider",
|
||||
},
|
||||
{
|
||||
type: "link",
|
||||
title: "Workflows",
|
||||
link: "/v2/resources/medusa-workflows-reference",
|
||||
},
|
||||
{
|
||||
type: "link",
|
||||
title: "Data Model API",
|
||||
link: "/v2/resources/references/data-model",
|
||||
},
|
||||
],
|
||||
},
|
||||
]
|
||||
|
||||
export const navDropdownItemsV1: NavigationDropdownItem[] = [
|
||||
{
|
||||
type: "link",
|
||||
path: `/`,
|
||||
icon: NavigationDropdownDocV1Icon,
|
||||
title: "Documentation",
|
||||
},
|
||||
{
|
||||
type: "link",
|
||||
path: `/user-guide`,
|
||||
icon: NavigationDropdownUserIcon,
|
||||
title: "User Guide",
|
||||
},
|
||||
{
|
||||
type: "link",
|
||||
path: `/api/store`,
|
||||
icon: NavigationDropdownStoreIcon,
|
||||
title: "Store API",
|
||||
},
|
||||
{
|
||||
type: "link",
|
||||
path: `/api/admin`,
|
||||
icon: NavigationDropdownAdminIcon,
|
||||
title: "Admin API",
|
||||
},
|
||||
{
|
||||
type: "link",
|
||||
path: `/ui`,
|
||||
icon: NavigationDropdownUiIcon,
|
||||
title: "UI",
|
||||
},
|
||||
{
|
||||
type: "link",
|
||||
path: `/v2`,
|
||||
icon: NavigationDropdownDocIcon,
|
||||
title: "Medusa v2",
|
||||
},
|
||||
]
|
||||
|
||||
export const mobileSidebarItemsV1: SidebarItem[] = [
|
||||
{
|
||||
type: "link",
|
||||
title: "Docs",
|
||||
path: `/`,
|
||||
loaded: true,
|
||||
isPathHref: true,
|
||||
},
|
||||
{
|
||||
type: "link",
|
||||
title: "User Guide",
|
||||
path: `/user-guide`,
|
||||
loaded: true,
|
||||
isPathHref: true,
|
||||
},
|
||||
{
|
||||
type: "link",
|
||||
title: "Store API",
|
||||
path: `/api/store`,
|
||||
loaded: true,
|
||||
isPathHref: true,
|
||||
},
|
||||
{
|
||||
type: "link",
|
||||
title: "Admin API",
|
||||
path: `/api/admin`,
|
||||
loaded: true,
|
||||
isPathHref: true,
|
||||
},
|
||||
{
|
||||
type: "link",
|
||||
title: "UI",
|
||||
path: `/ui`,
|
||||
loaded: true,
|
||||
isPathHref: true,
|
||||
},
|
||||
{
|
||||
type: "link",
|
||||
title: "Learn Medusa V2",
|
||||
path: `/v2`,
|
||||
loaded: true,
|
||||
isPathHref: true,
|
||||
additionalElms: <Badge variant="blue">v2</Badge>,
|
||||
},
|
||||
]
|
||||
|
||||
export const mobileSidebarItemsV2: SidebarItem[] = [
|
||||
{
|
||||
type: "link",
|
||||
title: "Docs",
|
||||
path: `/v2`,
|
||||
loaded: true,
|
||||
isPathHref: true,
|
||||
},
|
||||
{
|
||||
type: "link",
|
||||
title: "Learning Resources",
|
||||
path: `/v2/resources`,
|
||||
loaded: true,
|
||||
isPathHref: true,
|
||||
},
|
||||
{
|
||||
type: "link",
|
||||
title: "Store API",
|
||||
path: `/v2/api/store`,
|
||||
loaded: true,
|
||||
isPathHref: true,
|
||||
},
|
||||
{
|
||||
type: "link",
|
||||
title: "Admin API",
|
||||
path: `/v2/api/admin`,
|
||||
loaded: true,
|
||||
isPathHref: true,
|
||||
},
|
||||
{
|
||||
type: "link",
|
||||
title: "UI",
|
||||
path: `/ui`,
|
||||
loaded: true,
|
||||
isPathHref: true,
|
||||
},
|
||||
{
|
||||
type: "link",
|
||||
title: "Medusa v1",
|
||||
path: `/`,
|
||||
loaded: true,
|
||||
isPathHref: true,
|
||||
},
|
||||
]
|
||||
|
||||
export const searchFiltersV2: OptionType[] = [
|
||||
export const searchFilters: OptionType[] = [
|
||||
{
|
||||
value: "guides",
|
||||
label: "Guides",
|
||||
@@ -206,36 +129,9 @@ export const searchFiltersV2: OptionType[] = [
|
||||
value: "store-v2",
|
||||
label: "Store API (v2)",
|
||||
},
|
||||
// TODO add more filters
|
||||
]
|
||||
|
||||
export const searchFiltersV1: OptionType[] = [
|
||||
{
|
||||
value: "admin",
|
||||
label: "Admin API",
|
||||
},
|
||||
{
|
||||
value: "store",
|
||||
label: "Store API",
|
||||
},
|
||||
{
|
||||
value: "docs",
|
||||
label: "Docs",
|
||||
},
|
||||
{
|
||||
value: "user-guide",
|
||||
label: "User Guide",
|
||||
},
|
||||
{
|
||||
value: "plugins",
|
||||
label: "Plugins",
|
||||
},
|
||||
{
|
||||
value: "reference",
|
||||
label: "References",
|
||||
},
|
||||
{
|
||||
value: "ui",
|
||||
label: "UI",
|
||||
label: "Medusa UI",
|
||||
},
|
||||
// TODO add more filters
|
||||
]
|
||||
|
||||
@@ -50,7 +50,8 @@ export const MainContentLayout = ({
|
||||
"flex-col items-center",
|
||||
"h-full w-full",
|
||||
"overflow-y-scroll overflow-x-hidden",
|
||||
"md:rounded-t-docs_DEFAULT shadow-elevation-card-rest",
|
||||
"md:rounded-t-docs_DEFAULT",
|
||||
"shadow-elevation-card-rest dark:shadow-elevation-card-rest-dark",
|
||||
mainWrapperClasses
|
||||
)}
|
||||
id="main"
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import React from "react"
|
||||
import clsx from "clsx"
|
||||
import { RootProviders, Sidebar, SidebarProps } from "@/components"
|
||||
import { MobileNavigation } from "../components/MobileNavigation"
|
||||
import { Toc } from "../components/Toc"
|
||||
import { MainContentLayout, MainContentLayoutProps } from "./main-content"
|
||||
|
||||
@@ -14,6 +13,7 @@ export type RootLayoutProps = {
|
||||
showPagination?: boolean
|
||||
feedbackComponent?: React.ReactNode
|
||||
editComponent?: React.ReactNode
|
||||
showBreadcrumbs?: boolean
|
||||
} & MainContentLayoutProps
|
||||
|
||||
export const RootLayout = ({
|
||||
@@ -38,7 +38,6 @@ export const RootLayout = ({
|
||||
>
|
||||
<RootProviders>
|
||||
<ProvidersComponent>
|
||||
<MobileNavigation />
|
||||
<Sidebar {...sidebarProps} />
|
||||
<div className={clsx("relative", "h-screen", "flex")}>
|
||||
<MainContentLayout {...mainProps} />
|
||||
|
||||
@@ -1,13 +1,14 @@
|
||||
import React from "react"
|
||||
import { RootLayout, RootLayoutProps } from "./root"
|
||||
import clsx from "clsx"
|
||||
import { Pagination } from ".."
|
||||
import { Breadcrumbs, Pagination } from ".."
|
||||
|
||||
export const TightLayout = ({
|
||||
children,
|
||||
showPagination,
|
||||
feedbackComponent,
|
||||
editComponent,
|
||||
showBreadcrumbs = true,
|
||||
...props
|
||||
}: RootLayoutProps) => {
|
||||
return (
|
||||
@@ -21,6 +22,7 @@ export const TightLayout = ({
|
||||
"px-docs_1 md:px-docs_4 lg:px-0"
|
||||
)}
|
||||
>
|
||||
{showBreadcrumbs && <Breadcrumbs />}
|
||||
{children}
|
||||
{feedbackComponent}
|
||||
{showPagination && <Pagination />}
|
||||
|
||||
@@ -1,13 +1,14 @@
|
||||
import React from "react"
|
||||
import { RootLayout, RootLayoutProps } from "./root"
|
||||
import clsx from "clsx"
|
||||
import { Pagination } from ".."
|
||||
import { Breadcrumbs, Pagination } from ".."
|
||||
|
||||
export const WideLayout = ({
|
||||
children,
|
||||
showPagination,
|
||||
feedbackComponent,
|
||||
editComponent,
|
||||
showBreadcrumbs = true,
|
||||
...props
|
||||
}: RootLayoutProps) => {
|
||||
return (
|
||||
@@ -22,6 +23,7 @@ export const WideLayout = ({
|
||||
"lg:max-w-lg-wide-content xl:max-w-xl-wide-content relative mt-4 w-full flex-1 lg:mt-7"
|
||||
)}
|
||||
>
|
||||
{showBreadcrumbs && <Breadcrumbs />}
|
||||
{children}
|
||||
{feedbackComponent}
|
||||
{showPagination && <Pagination />}
|
||||
|
||||
@@ -1,27 +1,24 @@
|
||||
"use client"
|
||||
|
||||
import { usePathname } from "next/navigation"
|
||||
import React, { createContext, useContext, useMemo } from "react"
|
||||
import {
|
||||
BreadcrumbOptions,
|
||||
NavigationDropdownItem,
|
||||
NavigationDropdownItemLink,
|
||||
} from "types"
|
||||
import { NavigationItem } from "types"
|
||||
import { useSiteConfig } from "../SiteConifg"
|
||||
|
||||
export type MainNavContext = {
|
||||
navItems: NavigationDropdownItem[]
|
||||
activeItem?: NavigationDropdownItemLink
|
||||
navItems: NavigationItem[]
|
||||
activeItemIndex?: number
|
||||
activeItem?: NavigationItem
|
||||
reportIssueLink: string
|
||||
editDate?: string
|
||||
breadcrumbOptions: BreadcrumbOptions
|
||||
}
|
||||
|
||||
const MainNavContext = createContext<MainNavContext | null>(null)
|
||||
|
||||
export type MainNavProviderProps = {
|
||||
navItems: NavigationDropdownItem[]
|
||||
navItems: NavigationItem[]
|
||||
reportIssueLink: string
|
||||
editDate?: string
|
||||
breadcrumbOptions?: BreadcrumbOptions
|
||||
children?: React.ReactNode
|
||||
}
|
||||
|
||||
@@ -30,26 +27,72 @@ export const MainNavProvider = ({
|
||||
reportIssueLink,
|
||||
children,
|
||||
editDate,
|
||||
breadcrumbOptions = {
|
||||
showCategories: true,
|
||||
},
|
||||
}: MainNavProviderProps) => {
|
||||
const activeItem = useMemo(
|
||||
() =>
|
||||
navItems.find(
|
||||
(item) => item.type === "link" && item.isActive
|
||||
) as NavigationDropdownItemLink,
|
||||
[navItems]
|
||||
)
|
||||
const pathname = usePathname()
|
||||
const { config } = useSiteConfig()
|
||||
|
||||
const baseUrl = `${config.baseUrl}${config.basePath}`
|
||||
|
||||
const activeItemIndex = useMemo(() => {
|
||||
const currentUrl = `${baseUrl}${pathname}`.replace(/\/$/, "")
|
||||
|
||||
let fallbackIndex: number | undefined
|
||||
|
||||
const index = navItems.findIndex((item, index) => {
|
||||
if (item.type === "dropdown") {
|
||||
return item.children.some((childItem) => {
|
||||
if (childItem.type !== "link") {
|
||||
return
|
||||
}
|
||||
|
||||
const isItemActive = currentUrl.startsWith(childItem.link)
|
||||
|
||||
if (
|
||||
isItemActive &&
|
||||
childItem.useAsFallback &&
|
||||
fallbackIndex === undefined
|
||||
) {
|
||||
fallbackIndex = index
|
||||
return false
|
||||
}
|
||||
|
||||
return isItemActive
|
||||
})
|
||||
}
|
||||
|
||||
if (item.project && item.project !== config.project.key) {
|
||||
return false
|
||||
}
|
||||
|
||||
const isItemActive = currentUrl.startsWith(item.path)
|
||||
|
||||
if (isItemActive && item.useAsFallback && fallbackIndex === undefined) {
|
||||
fallbackIndex = index
|
||||
return false
|
||||
}
|
||||
|
||||
return isItemActive
|
||||
})
|
||||
|
||||
return index !== -1 ? index : fallbackIndex
|
||||
}, [navItems, pathname, baseUrl, config])
|
||||
|
||||
const activeItem = useMemo(() => {
|
||||
if (activeItemIndex === undefined) {
|
||||
return
|
||||
}
|
||||
|
||||
return navItems[activeItemIndex]
|
||||
}, [navItems, activeItemIndex])
|
||||
|
||||
return (
|
||||
<MainNavContext.Provider
|
||||
value={{
|
||||
navItems,
|
||||
activeItem,
|
||||
activeItemIndex,
|
||||
reportIssueLink,
|
||||
editDate,
|
||||
breadcrumbOptions,
|
||||
activeItem,
|
||||
}}
|
||||
>
|
||||
{children}
|
||||
|
||||
@@ -26,6 +26,13 @@ export const SiteConfigProvider = ({
|
||||
default: [],
|
||||
mobile: [],
|
||||
},
|
||||
project: {
|
||||
title: "",
|
||||
key: "",
|
||||
},
|
||||
breadcrumbOptions: {
|
||||
showCategories: true,
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
@@ -1,25 +0,0 @@
|
||||
import { SidebarItem } from "types"
|
||||
import { mobileSidebarItemsV1, mobileSidebarItemsV2 } from ".."
|
||||
|
||||
type Options = {
|
||||
baseUrl: string
|
||||
version?: "v1" | "v2"
|
||||
}
|
||||
|
||||
export function getMobileSidebarItems({
|
||||
baseUrl,
|
||||
version = "v1",
|
||||
}: Options): SidebarItem[] {
|
||||
const mobileItems =
|
||||
version === "v2" ? mobileSidebarItemsV2 : mobileSidebarItemsV1
|
||||
return mobileItems.map((item) => {
|
||||
if (item.type !== "link") {
|
||||
return item
|
||||
}
|
||||
|
||||
return {
|
||||
...item,
|
||||
path: `${baseUrl}${item.path}`,
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -1,27 +1,31 @@
|
||||
import { NavigationDropdownItem } from "types"
|
||||
import { navDropdownItemsV1, navDropdownItemsV2 } from ".."
|
||||
import { NavigationItem } from "types"
|
||||
import { navDropdownItems } from ".."
|
||||
|
||||
type Options = {
|
||||
basePath: string
|
||||
activePath: string
|
||||
version?: "v1" | "v2"
|
||||
}
|
||||
|
||||
export function getNavDropdownItems({
|
||||
basePath,
|
||||
activePath,
|
||||
version = "v1",
|
||||
}: Options): NavigationDropdownItem[] {
|
||||
const items = version === "v2" ? navDropdownItemsV2 : navDropdownItemsV1
|
||||
return items.map((item) => {
|
||||
if (item.type === "divider") {
|
||||
return item
|
||||
export function getNavDropdownItems({ basePath }: Options): NavigationItem[] {
|
||||
return navDropdownItems.map((item) => {
|
||||
const newItem = {
|
||||
...item,
|
||||
}
|
||||
|
||||
return {
|
||||
...item,
|
||||
isActive: activePath === item.path,
|
||||
path: `${basePath}${item.path}`,
|
||||
if (newItem.type === "link") {
|
||||
newItem.path = `${basePath}${newItem.path}`
|
||||
} else {
|
||||
newItem.children = newItem.children.map((childItem) => {
|
||||
if (childItem.type !== "link") {
|
||||
return childItem
|
||||
}
|
||||
|
||||
return {
|
||||
...childItem,
|
||||
link: `${basePath}${childItem.link}`,
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
return newItem
|
||||
})
|
||||
}
|
||||
|
||||
@@ -5,7 +5,6 @@ export * from "./decode-str"
|
||||
export * from "./dom-utils"
|
||||
export * from "./format-report-link"
|
||||
export * from "./get-link-with-base-path"
|
||||
export * from "./get-mobile-sidebar-items"
|
||||
export * from "./get-navbar-items"
|
||||
export * from "./get-os-shortcut"
|
||||
export * from "./get-scrolled-top"
|
||||
|
||||
Reference in New Issue
Block a user