change main navbar

This commit is contained in:
Shahed Nasser
2025-03-10 17:19:23 +02:00
parent 0c71bce1e2
commit 0ba63ac29e
17 changed files with 260 additions and 152 deletions

View File

@@ -883,10 +883,6 @@ export const filesMap = [
"filePath": "/www/apps/resources/app/plugins/guides/wishlist/page.mdx",
"pathname": "/plugins/guides/wishlist"
},
{
"filePath": "/www/apps/resources/app/plugins/page.mdx",
"pathname": "/plugins"
},
{
"filePath": "/www/apps/resources/app/recipes/b2b/page.mdx",
"pathname": "/recipes/b2b"

View File

@@ -6401,6 +6401,7 @@ const generatedgeneratedReferencesSidebarSidebar = {
"type": "category",
"title": "Steps",
"autogenerate_path": "/references/helper_steps/functions",
"initialOpen": true,
"children": [
{
"loaded": true,
@@ -6502,6 +6503,7 @@ const generatedgeneratedReferencesSidebarSidebar = {
"isPathHref": true,
"type": "category",
"title": "Methods",
"initialOpen": true,
"autogenerate_path": "/service-factory-reference/methods",
"children": [
{
@@ -6583,6 +6585,7 @@ const generatedgeneratedReferencesSidebarSidebar = {
"isPathHref": true,
"type": "category",
"title": "Tips",
"initialOpen": true,
"autogenerate_path": "/service-factory-reference/tips",
"children": [
{
@@ -6622,6 +6625,7 @@ const generatedgeneratedReferencesSidebarSidebar = {
"isPathHref": true,
"type": "category",
"title": "Functions",
"initialOpen": true,
"children": [
{
"loaded": true,
@@ -6668,6 +6672,7 @@ const generatedgeneratedReferencesSidebarSidebar = {
"isPathHref": true,
"type": "category",
"title": "Functions",
"initialOpen": true,
"autogenerate_path": "/references/workflows/functions",
"children": [
{

View File

@@ -33,6 +33,7 @@ const generatedgeneratedToolsSidebarSidebar = {
"sidebar_id": "medusa-cli",
"title": "Medusa CLI",
"childSidebarTitle": "Medusa CLI Reference",
"initialOpen": true,
"children": [
{
"loaded": true,
@@ -756,6 +757,7 @@ const generatedgeneratedToolsSidebarSidebar = {
"isPathHref": true,
"type": "category",
"title": "Payment",
"initialOpen": true,
"children": [
{
"loaded": true,

View File

@@ -99,6 +99,7 @@ export const referencesSidebar = [
type: "category",
title: "Steps",
autogenerate_path: "/references/helper_steps/functions",
initialOpen: true,
},
],
},
@@ -120,11 +121,13 @@ export const referencesSidebar = [
{
type: "category",
title: "Methods",
initialOpen: true,
autogenerate_path: "/service-factory-reference/methods",
},
{
type: "category",
title: "Tips",
initialOpen: true,
autogenerate_path: "/service-factory-reference/tips",
},
],
@@ -146,6 +149,7 @@ export const referencesSidebar = [
{
type: "category",
title: "Functions",
initialOpen: true,
children: [
{
type: "link",
@@ -179,6 +183,7 @@ export const referencesSidebar = [
{
type: "category",
title: "Functions",
initialOpen: true,
autogenerate_path: "/references/workflows/functions",
},
],

View File

@@ -22,6 +22,7 @@ export const toolsSidebar = [
sidebar_id: "medusa-cli",
title: "Medusa CLI",
childSidebarTitle: "Medusa CLI Reference",
initialOpen: true,
children: [
{
type: "link",
@@ -100,6 +101,7 @@ export const toolsSidebar = [
{
type: "category",
title: "Payment",
initialOpen: true,
children: [
{
type: "link",

View File

@@ -5,6 +5,7 @@ import clsx from "clsx"
import React, { useRef, useState } from "react"
import { NavigationItemDropdown } from "types"
import { Menu } from "../../../.."
import { MainNavItemLink } from "../Link"
type MainNavItemDropdownProps = {
item: NavigationItemDropdown
@@ -22,13 +23,26 @@ export const MainNavItemDropdown = ({
const [isOpen, setIsOpen] = useState(false)
const ref = useRef<HTMLDivElement>(null)
return (
<div
className={clsx("relative", wrapperClassName)}
ref={ref}
onMouseOver={() => setIsOpen(true)}
onMouseLeave={() => setIsOpen(false)}
>
const getItemContent = () => {
if (item.link) {
return (
<MainNavItemLink
item={{
...item,
link: item.link!,
type: "link",
}}
isActive={isActive}
icon={
<TriangleDownMini
className={clsx("transition-transform", isOpen && "rotate-180")}
/>
}
/>
)
}
return (
<div
className={clsx(
"cursor-pointer flex gap-docs_0.25 items-center",
@@ -46,6 +60,17 @@ export const MainNavItemDropdown = ({
className={clsx("transition-transform", isOpen && "rotate-180")}
/>
</div>
)
}
return (
<div
className={clsx("relative", wrapperClassName)}
ref={ref}
onMouseOver={() => setIsOpen(true)}
onMouseLeave={() => setIsOpen(false)}
>
{getItemContent()}
<div className="absolute top-full -left-docs_0.75 pt-docs_0.25">
<Menu
className={clsx("min-w-[190px]", !isOpen && "hidden")}

View File

@@ -8,18 +8,24 @@ import clsx from "clsx"
type MainNavItemLinkProps = {
item: NavigationItemLink
isActive: boolean
icon?: React.ReactNode
}
export const MainNavItemLink = ({ item, isActive }: MainNavItemLinkProps) => {
export const MainNavItemLink = ({
item,
isActive,
icon,
}: MainNavItemLinkProps) => {
return (
<LinkButton
href={item.path}
href={item.link}
className={clsx(
isActive && "text-medusa-fg-base",
!isActive && "text-medusa-fg-muted hover:text-medusa-fg-subtle"
)}
>
{item.title}
{icon}
</LinkButton>
)
}

View File

@@ -8,11 +8,11 @@ import clsx from "clsx"
import { SelectedMenu } from ".."
type MainNavMobileMainMenu = {
setSelectedMenu: (menu: SelectedMenu) => void
setSelectedMenus: React.Dispatch<React.SetStateAction<SelectedMenu>>
}
export const MainNavMobileMainMenu = ({
setSelectedMenu,
setSelectedMenus: setSelectedMenu,
}: MainNavMobileMainMenu) => {
const { navItems } = useMainNav()
@@ -34,14 +34,17 @@ export const MainNavMobileMainMenu = ({
return
}
setSelectedMenu({
title: item.title,
menu: item.children,
})
setSelectedMenu((prev) => [
...prev,
{
title: item.title,
menu: item.children,
},
])
}}
>
{item.type === "link" && (
<Link href={item.path} className="block w-full">
<Link href={item.link} className="block w-full">
{item.title}
</Link>
)}

View File

@@ -3,19 +3,25 @@
import clsx from "clsx"
import Link from "next/link"
import React, { useMemo } from "react"
import { MenuItem, MenuItemLink } from "types"
import { MenuItem, MenuItemLink, MenuItemSubMenu } from "types"
import { SelectedMenu } from ".."
import { TriangleRightMini } from "@medusajs/icons"
type MainNavMobileSubMenuProps = {
menu: MenuItem[]
title: string
setSelectedMenus: React.Dispatch<React.SetStateAction<SelectedMenu>>
}
export const MainNavMobileSubMenu = ({
menu,
title,
setSelectedMenus,
}: MainNavMobileSubMenuProps) => {
const filteredItems: MenuItemLink[] = useMemo(() => {
return menu.filter((item) => item.type === "link") as MenuItemLink[]
const filteredItems: (MenuItemLink | MenuItemSubMenu)[] = useMemo(() => {
return menu.filter(
(item) => item.type === "link" || item.type === "sub-menu"
) as (MenuItemLink | MenuItemSubMenu)[]
}, [menu])
return (
<div className="flex flex-col gap-[23px]">
@@ -31,9 +37,28 @@ export const MainNavMobileSubMenu = ({
"flex justify-between gap-docs_1"
)}
>
<Link href={item.link} className="block w-full">
{item.title}
</Link>
{item.type === "link" && (
<Link href={item.link} className="block w-full">
{item.title}
</Link>
)}
{item.type === "sub-menu" && (
<div
className="w-full flex justify-between gap-docs_1"
onClick={() =>
setSelectedMenus((prev) => [
...prev,
{
title: item.title,
menu: item.items,
},
])
}
>
<span>{item.title}</span>
<TriangleRightMini />
</div>
)}
</li>
))}
</ul>

View File

@@ -13,11 +13,11 @@ 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 [selectedMenus, setSelectedMenus] = useState<SelectedMenu>([])
const ref = useRef(null)
return (
@@ -40,7 +40,11 @@ export const MainNavMobileMenu = () => {
>
<SwitchTransition>
<CSSTransition
key={!selectedMenu ? "main" : "sub"}
key={
!selectedMenus.length
? "main"
: selectedMenus[selectedMenus.length - 1].title
}
classNames={{
enter: "animate-fadeInLeft animate-fast",
exit: "animate-fadeOutRight animate-fast",
@@ -49,10 +53,10 @@ export const MainNavMobileMenu = () => {
timeout={250}
>
<div ref={ref} className="w-full px-docs_1.5">
{!selectedMenu && (
<MainNavMobileMainMenu setSelectedMenu={setSelectedMenu} />
{selectedMenus.length === 0 && (
<MainNavMobileMainMenu setSelectedMenus={setSelectedMenus} />
)}
{selectedMenu && (
{selectedMenus.length > 0 && (
<>
<div
className={clsx(
@@ -61,12 +65,21 @@ export const MainNavMobileMenu = () => {
"cursor-pointer"
)}
tabIndex={-1}
onClick={() => setSelectedMenu(undefined)}
onClick={() =>
setSelectedMenus((prev) => {
const temp = [...prev]
temp.pop()
return temp
})
}
>
<ArrowUturnLeft />
<span className="text-h1">Back</span>
</div>
<MainNavMobileSubMenu {...selectedMenu} />
<MainNavMobileSubMenu
{...selectedMenus[selectedMenus.length - 1]}
setSelectedMenus={setSelectedMenus}
/>
</>
)}
</div>

View File

@@ -0,0 +1,42 @@
"use client"
import React, { useState } from "react"
import { Menu, MenuProps } from ".."
import clsx from "clsx"
import { MenuItemSubMenu } from "types"
import { ChevronRight } from "@medusajs/icons"
type MenuSubMenuProps = Pick<MenuProps, "itemsOnClick"> & {
item: MenuItemSubMenu
}
export const MenuSubMenu = ({ item, itemsOnClick }: MenuSubMenuProps) => {
const [open, setOpen] = useState(false)
return (
<div
className="px-docs_0.25 relative"
onMouseOver={() => setOpen(true)}
onMouseLeave={() => setOpen(false)}
>
<span
className={clsx(
"flex py-docs_0.25 px-docs_0.5",
"gap-docs_0.5 rounded-docs_xs",
"hover:bg-medusa-bg-component-hover",
"text-medusa-fg-base justify-between"
)}
onClick={() => itemsOnClick?.(item)}
>
<span className="text-compact-small">{item.title}</span>
<span className="text-medusa-fg-subtle mt-[2.5px] block">
<ChevronRight />
</span>
</span>
{open && (
<div className="absolute top-0 left-[calc(100%-8px)] w-max">
<Menu itemsOnClick={itemsOnClick} items={item.items} />
</div>
)}
</div>
)
}

View File

@@ -4,6 +4,7 @@ import { MenuItem as MenuItemType } from "types"
import { MenuItem } from "./Item"
import { MenuDivider } from "./Divider"
import { MenuAction } from "./Action"
import { MenuSubMenu } from "./SubMenu"
export type MenuProps = {
items: MenuItemType[]
@@ -30,6 +31,9 @@ export const Menu = ({ items, className, itemsOnClick }: MenuProps) => {
)}
{item.type === "divider" && <MenuDivider />}
{item.type === "custom" && item.content}
{item.type === "sub-menu" && (
<MenuSubMenu item={item} itemsOnClick={itemsOnClick} />
)}
</React.Fragment>
))}
</div>

View File

@@ -7,7 +7,7 @@ export const GITHUB_ISSUES_LINK =
export const navDropdownItems: NavigationItem[] = [
{
type: "link",
path: `/learn`,
link: `/learn`,
title: "Get Started",
project: "book",
},
@@ -29,52 +29,50 @@ export const navDropdownItems: NavigationItem[] = [
},
{
type: "dropdown",
title: "Resources",
title: "Build",
children: [
{
type: "link",
title: "All Guides",
link: "/resources",
useAsFallback: true,
},
{
type: "link",
title: "Examples",
link: "/resources/examples",
},
{
type: "link",
title: "Recipes",
link: "/resources/recipes",
},
{
type: "divider",
type: "link",
title: "How-to & Tutorials",
link: "/resources/how-to-tutorials",
},
{
type: "link",
title: "Admin Components",
link: "/resources/admin-components",
title: "Integrations",
link: "/resources/integrations",
},
{
type: "link",
title: "Storefront Development",
title: "Storefront",
link: "/resources/storefront-development",
},
],
},
{
type: "dropdown",
title: "Tools & SDKs",
title: "Tools",
link: "/resources/tools",
children: [
{
type: "link",
title: "UI Library",
link: "/ui",
},
{
type: "link",
title: "Medusa CLI",
link: "/resources/medusa-cli",
type: "sub-menu",
title: "CLI Tools",
items: [
{
type: "link",
title: "create-medusa-app",
link: "/resources/create-medusa-app",
},
{
type: "link",
title: "Medusa CLI",
link: "/resources/medusa-cli",
},
],
},
{
type: "link",
@@ -88,77 +86,8 @@ export const navDropdownItems: NavigationItem[] = [
},
{
type: "link",
title: "create-medusa-app",
link: "/resources/create-medusa-app",
},
{
type: "divider",
},
{
type: "link",
title: "Integrations",
link: "/resources/integrations",
},
],
},
{
type: "dropdown",
title: "Framework",
children: [
{
type: "link",
title: "Modules",
link: "/learn/fundamentals/modules",
},
{
type: "link",
title: "API Routes",
link: "/learn/fundamentals/api-routes",
},
{
type: "link",
title: "Workflows",
link: "/learn/fundamentals/workflows",
},
{
type: "link",
title: "Data Models",
link: "/learn/fundamentals/data-models",
},
{
type: "link",
title: "Subscribers",
link: "/learn/fundamentals/events-and-subscribers",
},
{
type: "link",
title: "Scheduled Jobs",
link: "/learn/fundamentals/scheduled-jobs",
},
{
type: "link",
title: "Loaders",
link: "/learn/fundamentals/modules/loaders",
},
{
type: "link",
title: "Admin Customizations",
link: "/learn/fundamentals/admin",
},
{
type: "link",
title: "Plugins",
link: "/learn/fundamentals/plugins",
},
{
type: "link",
title: "Links",
link: "/learn/fundamentals/module-links",
},
{
type: "link",
title: "Query",
link: "/learn/fundamentals/module-links/query",
title: "Medusa UI",
link: "/ui",
},
],
},
@@ -179,6 +108,16 @@ export const navDropdownItems: NavigationItem[] = [
{
type: "divider",
},
{
type: "link",
title: "Admin Injection Zones",
link: "/resources/admin-widget-injection-zones",
},
{
type: "link",
title: "Container Resources",
link: "/resources/medusa-container-resources",
},
{
type: "link",
title: "Core Workflows",
@@ -189,11 +128,6 @@ export const navDropdownItems: NavigationItem[] = [
title: "Data Model Language",
link: "/resources/references/data-model",
},
{
type: "link",
title: "Service Factory",
link: "/resources/service-factory-reference",
},
{
type: "link",
title: "Events Reference",
@@ -201,15 +135,30 @@ export const navDropdownItems: NavigationItem[] = [
},
{
type: "link",
title: "Admin Widget Injection Zones",
link: "/resources/admin-widget-injection-zones",
title: "Helper Steps",
link: "/resources/references/helper-steps",
},
{
type: "link",
title: "Service Factory",
link: "/resources/service-factory-reference",
},
{
type: "link",
title: "Testing Framework",
link: "/resources/test-tools-reference",
},
{
type: "link",
title: "Workflows SDK",
link: "/resources/references/workflows",
},
],
},
{
type: "link",
title: "User Guide",
path: "/user-guide",
link: "/user-guide",
},
]

View File

@@ -59,7 +59,7 @@ export const MainNavProvider = ({
return false
}
const isItemActive = currentUrl.startsWith(item.path)
const isItemActive = currentUrl.startsWith(item.link)
if (isItemActive && item.useAsFallback && fallbackIndex === undefined) {
fallbackIndex = index

View File

@@ -1,4 +1,4 @@
import { NavigationItem } from "types"
import { MenuItem, NavigationItem } from "types"
import { navDropdownItems } from ".."
type Options = {
@@ -12,20 +12,43 @@ export function getNavDropdownItems({ basePath }: Options): NavigationItem[] {
}
if (newItem.type === "link") {
newItem.path = `${basePath}${newItem.path}`
newItem.link = `${basePath}${newItem.link}`
} else {
newItem.children = newItem.children.map((childItem) => {
if (childItem.type !== "link") {
return childItem
}
return {
...childItem,
link: `${basePath}${childItem.link}`,
}
newItem.children = normalizeMenuItems({
basePath,
items: newItem.children,
})
}
return newItem
})
}
export function normalizeMenuItems({
basePath,
items,
}: {
basePath: string
items: MenuItem[]
}): MenuItem[] {
return items.map((item) => {
if (item.type !== "link" && item.type !== "sub-menu") {
return item
}
if (item.type === "link") {
return {
...item,
link: `${basePath}${item.link}`,
}
}
return {
...item,
items: normalizeMenuItems({
basePath,
items: item.items,
}),
}
})
}

View File

@@ -22,8 +22,15 @@ export type MenuItemCustom = {
content: React.ReactNode
}
export type MenuItemSubMenu = {
type: "sub-menu"
items: MenuItem[]
title: string
}
export type MenuItem =
| MenuItemLink
| MenuItemDivider
| MenuItemAction
| MenuItemCustom
| MenuItemSubMenu

View File

@@ -7,11 +7,12 @@ export type NavigationItemDropdown = {
useAsFallback?: boolean
})[]
project?: string
link?: string
}
export type NavigationItemLink = {
type: "link"
path: string
link: string
title: string
project?: string
useAsFallback?: boolean