docs: redesigned navigation (#9525)

Redesign navigation bar to reflect new design and allow for dropdowns

Closes DX-943
This commit is contained in:
Shahed Nasser authored and GitHub committed 2024-10-11 07:10:00 +00:00
1 parent 7c5415ba3a
commit 49a91fd40e
63 files changed
+895 -939

No files matched your search

+1
View File
@@ -34,6 +34,7 @@ export default function RootLayout({
bodyClassName={clsx(inter.variable, robotoMono.variable)} bodyClassName={clsx(inter.variable, robotoMono.variable)}
showToc={false} showToc={false}
showBanner={false} showBanner={false}
showBreadcrumbs={false}
> >
{children} {children}
</WideLayout> </WideLayout>
+5 -5
View File
@@ -1,5 +1,4 @@
import { DocsConfig } from "types" import { DocsConfig } from "types"
import { getMobileSidebarItems } from "docs-ui"
const baseUrl = process.env.NEXT_PUBLIC_BASE_URL || "http://localhost:3000" const baseUrl = process.env.NEXT_PUBLIC_BASE_URL || "http://localhost:3000"
@@ -16,9 +15,10 @@ export const config: DocsConfig = {
loaded: true, loaded: true,
}, },
], ],
mobile: getMobileSidebarItems({ mobile: [],
baseUrl, },
version: "v2", project: {
}), title: "API Reference",
key: "api-reference",
}, },
} }
@@ -8,8 +8,6 @@ import {
} from "docs-ui" } from "docs-ui"
import { useMemo } from "react" import { useMemo } from "react"
import { config } from "../config" import { config } from "../config"
import { usePathname } from "next/navigation"
import basePathUrl from "../utils/base-path-url"
type MainNavProviderProps = { type MainNavProviderProps = {
children?: React.ReactNode children?: React.ReactNode
@@ -17,15 +15,12 @@ type MainNavProviderProps = {
export const MainNavProvider = ({ children }: MainNavProviderProps) => { export const MainNavProvider = ({ children }: MainNavProviderProps) => {
const { isBrowser } = useIsBrowser() const { isBrowser } = useIsBrowser()
const pathname = usePathname()
const navigationDropdownItems = useMemo( const navigationDropdownItems = useMemo(
() => () =>
getNavDropdownItems({ getNavDropdownItems({
basePath: config.baseUrl, basePath: config.baseUrl,
activePath: basePathUrl(pathname),
version: "v2",
}), }),
[pathname] []
) )
const reportLink = useMemo( const reportLink = useMemo(
+2 -2
View File
@@ -3,7 +3,7 @@
import { import {
usePageLoading, usePageLoading,
SearchProvider as UiSearchProvider, SearchProvider as UiSearchProvider,
searchFiltersV2, searchFilters,
AiAssistantIcon, AiAssistantIcon,
AiAssistantProvider, AiAssistantProvider,
} from "docs-ui" } from "docs-ui"
@@ -51,7 +51,7 @@ const SearchProvider = ({ children }: SearchProviderProps) => {
checkInternalPattern: new RegExp( checkInternalPattern: new RegExp(
`^${config.baseUrl}${basePathUrl(`/(admin|store)`)}` `^${config.baseUrl}${basePathUrl(`/(admin|store)`)}`
), ),
filterOptions: searchFiltersV2, filterOptions: searchFilters,
}} }}
commands={[ commands={[
{ {
+8 -1
View File
@@ -7,5 +7,12 @@ export const config: DocsConfig = {
titleSuffix: "Medusa v2 Docs", titleSuffix: "Medusa v2 Docs",
baseUrl, baseUrl,
basePath: process.env.NEXT_PUBLIC_BASE_PATH, basePath: process.env.NEXT_PUBLIC_BASE_PATH,
sidebar: sidebarConfig(baseUrl), sidebar: sidebarConfig,
project: {
title: "Documentation",
key: "book",
},
breadcrumbOptions: {
showCategories: false,
},
} }
+3 -8
View File
@@ -1,4 +1,4 @@
import { Badge, getMobileSidebarItems } from "docs-ui" import { Badge } from "docs-ui"
import type { SidebarConfig, SidebarItem } from "@/types" import type { SidebarConfig, SidebarItem } from "@/types"
import { sidebar } from "../sidebar.mjs" import { sidebar } from "../sidebar.mjs"
@@ -20,12 +20,7 @@ const normalizeSidebarItems = (items: SidebarItem[]) =>
return item return item
}) })
export const sidebarConfig = (baseUrl: string): SidebarConfig => { export const sidebarConfig: SidebarConfig = {
return {
default: normalizeSidebarItems(sidebar), default: normalizeSidebarItems(sidebar),
mobile: getMobileSidebarItems({ mobile: [],
baseUrl,
version: "v2",
}),
}
} }
-6
View File
@@ -8,7 +8,6 @@ import {
} from "docs-ui" } from "docs-ui"
import { useMemo } from "react" import { useMemo } from "react"
import { config } from "../config" import { config } from "../config"
import { basePathUrl } from "../utils/base-path-url"
import { usePathname } from "next/navigation" import { usePathname } from "next/navigation"
import { generatedEditDates } from "../generated/edit-dates.mjs" import { generatedEditDates } from "../generated/edit-dates.mjs"
@@ -23,8 +22,6 @@ export const MainNavProvider = ({ children }: MainNavProviderProps) => {
() => () =>
getNavDropdownItems({ getNavDropdownItems({
basePath: config.baseUrl, basePath: config.baseUrl,
activePath: basePathUrl(),
version: "v2",
}), }),
[] []
) )
@@ -51,9 +48,6 @@ export const MainNavProvider = ({ children }: MainNavProviderProps) => {
navItems={navigationDropdownItems} navItems={navigationDropdownItems}
reportIssueLink={reportLink} reportIssueLink={reportLink}
editDate={editDate} editDate={editDate}
breadcrumbOptions={{
showCategories: false,
}}
> >
{children} {children}
</UiMainNavProvider> </UiMainNavProvider>
+2 -2
View File
@@ -4,7 +4,7 @@ import {
AiAssistantIcon, AiAssistantIcon,
AiAssistantProvider, AiAssistantProvider,
SearchProvider as UiSearchProvider, SearchProvider as UiSearchProvider,
searchFiltersV2, searchFilters,
} from "docs-ui" } from "docs-ui"
import { config } from "../config" import { config } from "../config"
@@ -50,7 +50,7 @@ const SearchProvider = ({ children }: SearchProviderProps) => {
checkInternalPattern: new RegExp( checkInternalPattern: new RegExp(
`^${config.baseUrl}/v2/([^(resources)])*` `^${config.baseUrl}/v2/([^(resources)])*`
), ),
filterOptions: searchFiltersV2, filterOptions: searchFilters,
}} }}
commands={[ commands={[
{ {
+8 -5
View File
@@ -1,5 +1,4 @@
import { DocsConfig, SidebarItem } from "types" import { DocsConfig, SidebarItem } from "types"
import { getMobileSidebarItems } from "docs-ui"
import { generatedSidebar } from "../generated/sidebar.mjs" import { generatedSidebar } from "../generated/sidebar.mjs"
const baseUrl = process.env.NEXT_PUBLIC_BASE_URL || "http://localhost:3000" const baseUrl = process.env.NEXT_PUBLIC_BASE_URL || "http://localhost:3000"
@@ -10,9 +9,13 @@ export const config: DocsConfig = {
basePath: process.env.NEXT_PUBLIC_BASE_PATH, basePath: process.env.NEXT_PUBLIC_BASE_PATH,
sidebar: { sidebar: {
default: generatedSidebar as SidebarItem[], default: generatedSidebar as SidebarItem[],
mobile: getMobileSidebarItems({ mobile: [],
baseUrl, },
version: "v2", project: {
}), title: "Development Resources",
key: "resources",
},
breadcrumbOptions: {
showCategories: true,
}, },
} }
+1 -8
View File
@@ -8,7 +8,6 @@ import {
} from "docs-ui" } from "docs-ui"
import { useMemo } from "react" import { useMemo } from "react"
import { config } from "../config" import { config } from "../config"
import { basePathUrl } from "../utils/base-path-url"
import { usePathname } from "next/navigation" import { usePathname } from "next/navigation"
import { generatedEditDates } from "../generated/edit-dates.mjs" import { generatedEditDates } from "../generated/edit-dates.mjs"
@@ -23,14 +22,8 @@ export const MainNavProvider = ({ children }: MainNavProviderProps) => {
() => () =>
getNavDropdownItems({ getNavDropdownItems({
basePath: config.baseUrl, basePath: config.baseUrl,
activePath: basePathUrl(
pathname.startsWith("/commerce-modules")
? "/commerce-modules"
: undefined
),
version: "v2",
}), }),
[pathname] []
) )
const reportLink = useMemo( const reportLink = useMemo(
+2 -2
View File
@@ -4,7 +4,7 @@ import {
AiAssistantIcon, AiAssistantIcon,
AiAssistantProvider, AiAssistantProvider,
SearchProvider as UiSearchProvider, SearchProvider as UiSearchProvider,
searchFiltersV2, searchFilters,
} from "docs-ui" } from "docs-ui"
import { config } from "../config" import { config } from "../config"
@@ -39,7 +39,7 @@ const SearchProvider = ({ children }: SearchProviderProps) => {
}, },
], ],
checkInternalPattern: new RegExp(`^${config.baseUrl}/v2/resources/.*`), checkInternalPattern: new RegExp(`^${config.baseUrl}/v2/resources/.*`),
filterOptions: searchFiltersV2, filterOptions: searchFilters,
}} }}
commands={[ commands={[
{ {
+1 -6
View File
@@ -1,6 +1,4 @@
import { getMobileSidebarItems } from "docs-ui"
import { SidebarSectionItems } from "types" import { SidebarSectionItems } from "types"
import { siteConfig } from "./site"
type DocsConfig = { type DocsConfig = {
sidebar: SidebarSectionItems sidebar: SidebarSectionItems
@@ -359,9 +357,6 @@ export const docsConfig: DocsConfig = {
], ],
}, },
], ],
mobile: getMobileSidebarItems({ mobile: [],
baseUrl: siteConfig.baseUrl,
version: "v1",
}),
}, },
} }
+7
View File
@@ -19,4 +19,11 @@ export const siteConfig: SiteConfig = {
default: [], default: [],
mobile: [], mobile: [],
}, },
project: {
title: "Medusa UI",
key: "ui",
},
breadcrumbOptions: {
showCategories: true,
},
} }
-3
View File
@@ -8,7 +8,6 @@ import {
} from "docs-ui" } from "docs-ui"
import { useMemo } from "react" import { useMemo } from "react"
import { siteConfig } from "../config/site" import { siteConfig } from "../config/site"
import { basePathUrl } from "../lib/base-path-url"
type MainNavProviderProps = { type MainNavProviderProps = {
children?: React.ReactNode children?: React.ReactNode
@@ -20,8 +19,6 @@ export const MainNavProvider = ({ children }: MainNavProviderProps) => {
() => () =>
getNavDropdownItems({ getNavDropdownItems({
basePath: siteConfig.baseUrl, basePath: siteConfig.baseUrl,
activePath: basePathUrl(),
version: "v1",
}), }),
[] []
) )
+2 -2
View File
@@ -4,7 +4,7 @@ import {
AiAssistantIcon, AiAssistantIcon,
AiAssistantProvider, AiAssistantProvider,
SearchProvider as UiSearchProvider, SearchProvider as UiSearchProvider,
searchFiltersV1, searchFilters,
} from "docs-ui" } from "docs-ui"
import { absoluteUrl } from "../lib/absolute-url" import { absoluteUrl } from "../lib/absolute-url"
@@ -34,7 +34,7 @@ const SearchProvider = ({ children }: SearchProviderProps) => {
}, },
], ],
checkInternalPattern: new RegExp(`^${absoluteUrl()}/ui`), checkInternalPattern: new RegExp(`^${absoluteUrl()}/ui`),
filterOptions: searchFiltersV1, filterOptions: searchFilters,
}} }}
initialDefaultFilters={["ui"]} initialDefaultFilters={["ui"]}
commands={[ commands={[
+6
View File
@@ -30,6 +30,12 @@
@apply text-ui-fg-subtle; @apply text-ui-fg-subtle;
} }
/* Hack to hide navbar / toc when some components like prompt are opened. */
body[data-scroll-locked] .z-20,
body[data-scroll-locked] .z-10 {
z-index: 0 !important;
}
body[data-modal="opened"] { body[data-modal="opened"] {
@apply !overflow-hidden text-ui-fg-base; @apply !overflow-hidden text-ui-fg-base;
} }
+8 -5
View File
@@ -1,5 +1,4 @@
import { DocsConfig, SidebarItem } from "types" import { DocsConfig, SidebarItem } from "types"
import { getMobileSidebarItems } from "docs-ui"
import { generatedSidebar as sidebar } from "@/generated/sidebar.mjs" import { generatedSidebar as sidebar } from "@/generated/sidebar.mjs"
const baseUrl = process.env.NEXT_PUBLIC_BASE_URL || "http://localhost:3000" const baseUrl = process.env.NEXT_PUBLIC_BASE_URL || "http://localhost:3000"
@@ -10,9 +9,13 @@ export const config: DocsConfig = {
basePath: process.env.NEXT_PUBLIC_BASE_PATH, basePath: process.env.NEXT_PUBLIC_BASE_PATH,
sidebar: { sidebar: {
default: sidebar as SidebarItem[], default: sidebar as SidebarItem[],
mobile: getMobileSidebarItems({ mobile: [],
baseUrl, },
version: "v2", project: {
}), title: "User Guide",
key: "user-guide",
},
breadcrumbOptions: {
showCategories: true,
}, },
} }
@@ -8,7 +8,6 @@ import {
} from "docs-ui" } from "docs-ui"
import { useMemo } from "react" import { useMemo } from "react"
import { config } from "../config" import { config } from "../config"
import { basePathUrl } from "../utils/base-path-url"
type MainNavProviderProps = { type MainNavProviderProps = {
children?: React.ReactNode children?: React.ReactNode
@@ -20,8 +19,6 @@ export const MainNavProvider = ({ children }: MainNavProviderProps) => {
() => () =>
getNavDropdownItems({ getNavDropdownItems({
basePath: config.baseUrl, basePath: config.baseUrl,
activePath: basePathUrl(),
version: "v2",
}), }),
[] []
) )
+4 -3
View File
@@ -4,7 +4,7 @@ import {
SearchProvider as UiSearchProvider, SearchProvider as UiSearchProvider,
AiAssistantIcon, AiAssistantIcon,
AiAssistantProvider, AiAssistantProvider,
searchFiltersV1, searchFilters,
} from "docs-ui" } from "docs-ui"
import { config } from "../config" import { config } from "../config"
@@ -42,9 +42,10 @@ const SearchProvider = ({ children }: SearchProviderProps) => {
}, },
], ],
checkInternalPattern: new RegExp(`^${config.baseUrl}/user-guide`), checkInternalPattern: new RegExp(`^${config.baseUrl}/user-guide`),
filterOptions: searchFiltersV1, filterOptions: searchFilters,
}} }}
initialDefaultFilters={["user-guide"]} // TODO change later when we have a user guide filter
initialDefaultFilters={["guides"]}
commands={[ commands={[
{ {
name: "ai-assistant", name: "ai-assistant",
@@ -1,29 +1,55 @@
"use client" "use client"
import React, { useMemo } from "react" import React, { useMemo } from "react"
import { CurrentItemsState, useSidebar } from "@/providers"
import { TriangleRightMini } from "@medusajs/icons"
import Link from "next/link"
import clsx from "clsx" import clsx from "clsx"
import Link from "next/link"
type BreadcrumbItem = Map<string, string> import { SidebarItemLink } from "types"
import { CurrentItemsState, useSidebar, useSiteConfig } from "../../providers"
import { Button } from "../Button"
import { TriangleRightMini } from "@medusajs/icons"
export const Breadcrumbs = () => { export const Breadcrumbs = () => {
const { currentItems } = useSidebar() const { currentItems, activeItem: sidebarActiveItem } = useSidebar()
const {
config: { breadcrumbOptions, project, baseUrl, basePath },
} = useSiteConfig()
const getBreadcrumbsOfItem = (item: CurrentItemsState): BreadcrumbItem => { const getLinkPath = (item?: SidebarItemLink): string | undefined => {
let tempBreadcrumbItems: BreadcrumbItem = new Map() 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) { if (item.previousSidebar) {
tempBreadcrumbItems = getBreadcrumbsOfItem(item.previousSidebar) tempBreadcrumbItems = getBreadcrumbsOfItem(item.previousSidebar)
} }
const parentPath = 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 = 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( tempBreadcrumbItems.set(
parentPath || firstItemPath || "/", breadcrumbPath,
item.parentItem?.childSidebarTitle || item.parentItem?.title || "" item.parentItem?.childSidebarTitle || item.parentItem?.title || ""
) )
@@ -31,51 +57,65 @@ export const Breadcrumbs = () => {
} }
const breadcrumbItems = useMemo(() => { const breadcrumbItems = useMemo(() => {
const tempBreadcrumbItems: BreadcrumbItem = new Map() const tempBreadcrumbItems: Map<string, string> = new Map()
if (!currentItems) { tempBreadcrumbItems.set(`${baseUrl}${basePath}`, project.title)
return tempBreadcrumbItems
}
tempBreadcrumbItems.set("/", "Home")
if (currentItems) {
getBreadcrumbsOfItem(currentItems).forEach((value, key) => getBreadcrumbsOfItem(currentItems).forEach((value, key) =>
tempBreadcrumbItems.set(key, value) 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 return tempBreadcrumbItems
}, [currentItems]) }, [currentItems, sidebarActiveItem, breadcrumbOptions])
const getBreadcrumbItemElms = (): React.ReactNode[] => { return (
const elms: React.ReactNode[] = [] <div
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( className={clsx(
"text-compact-x-small-plus text-medusa-fg-muted", "flex items-center gap-docs_0.25",
"hover:text-medusa-fg-subtle transition-colors" "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} {title}
</Link> </Link>
</Button>
</React.Fragment> </React.Fragment>
) ))}
})
return elms
}
return (
<>
{breadcrumbItems.size > 0 && (
<div className="flex gap-docs_0.25 items-center mb-docs_1">
{...getBreadcrumbItemElms()}
</div> </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 ( return (
<> <>
<span className="text-compact-small"> <span className="text-compact-small-plus">
Edited {dateMatch.groups.month} {dateObj.getDate()} Edited {dateMatch.groups.month} {dateObj.getDate()}
{dateObj.getFullYear() !== today.getFullYear() {dateObj.getFullYear() !== today.getFullYear()
? `, ${dateObj.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 clsx from "clsx"
import React from "react" import React from "react"
import { MainNavigationDropdown } from "./NavigationDropdown"
import { MainNavBreadcrumbs } from "./Breadcrumb"
import { import {
BorderedIcon,
Button, Button,
LinkButton, LinkButton,
SearchModalOpener, SearchModalOpener,
useMainNav, useMainNav,
useSidebar, useSidebar,
} from "../.." } 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 { 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 = () => { export const MainNav = () => {
const { reportIssueLink, editDate } = useMainNav() const { reportIssueLink, editDate } = useMainNav()
const { setMobileSidebarOpen } = useSidebar() const { setMobileSidebarOpen } = useSidebar()
return ( return (
<div <div
className={clsx( className={clsx(
"hidden sm:flex justify-between items-center", "flex justify-between items-center",
"px-docs_1 py-docs_0.75 w-full z-20", "px-docs_1 w-full z-20",
"sticky top-0 bg-medusa-bg-base" "sticky top-0 bg-medusa-bg-base"
)} )}
> >
<div className="flex items-center gap-docs_0.25"> <div className="flex items-center gap-docs_1">
<div className="flex items-center gap-[10px]">
<Button <Button
className="lg:hidden" className="lg:hidden my-docs_0.75 !p-[6.5px]"
variant="transparent-clear" variant="transparent-clear"
onClick={() => setMobileSidebarOpen(true)} onClick={() => setMobileSidebarOpen(true)}
> >
<SidebarLeftIcon /> <SidebarLeftIcon />
</Button> </Button>
<MainNavSidebarOpener /> <BorderedIcon
<MainNavigationDropdown /> IconComponent={MedusaIcon}
<MainNavBreadcrumbs /> iconWrapperClassName="my-[14px]"
/>
</div> </div>
<div className="flex items-center gap-docs_0.75"> <MainNavItems />
<div className="flex items-center gap-[6px] text-medusa-fg-muted"> </div>
<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} />} {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 Report Issue
</LinkButton> </LinkButton>
</div> </div>
<MainNavDivider />
<div className="flex items-center gap-docs_0.25"> <div className="flex items-center gap-docs_0.25">
<MainNavHelpButton />
<MainNavColorMode />
<SearchModalOpener /> <SearchModalOpener />
<MainNavDesktopMenu />
<MainNavMobileMenu />
</div> </div>
</div> </div>
</div> </div>
@@ -2,13 +2,14 @@
import clsx from "clsx" import clsx from "clsx"
import React from "react" import React from "react"
import { MenuItemAction } from "types" import { MenuItem, MenuItemAction } from "types"
export type MenuActionProps = { export type MenuActionProps = {
item: MenuItemAction item: MenuItemAction
onClick?: (item: MenuItem) => void
} }
export const MenuAction = ({ item }: MenuActionProps) => { export const MenuAction = ({ item, onClick }: MenuActionProps) => {
return ( return (
<div className="px-docs_0.25"> <div className="px-docs_0.25">
<span <span
@@ -19,7 +20,10 @@ export const MenuAction = ({ item }: MenuActionProps) => {
"text-medusa-fg-base cursor-pointer" "text-medusa-fg-base cursor-pointer"
)} )}
tabIndex={-1} tabIndex={-1}
onClick={item.action} onClick={() => {
item.action()
onClick?.(item)
}}
> >
<span className="text-medusa-fg-subtle mt-[2.5px] block"> <span className="text-medusa-fg-subtle mt-[2.5px] block">
{item.icon} {item.icon}
@@ -3,13 +3,14 @@
import clsx from "clsx" import clsx from "clsx"
import Link from "next/link" import Link from "next/link"
import React from "react" import React from "react"
import { MenuItemLink } from "types" import { MenuItem as MenuItemType, MenuItemLink } from "types"
export type MenuItemProps = { export type MenuItemProps = {
item: MenuItemLink item: MenuItemLink
onClick?: (item: MenuItemType) => void
} }
export const MenuItem = ({ item }: MenuItemProps) => { export const MenuItem = ({ item, onClick }: MenuItemProps) => {
return ( return (
<div className="px-docs_0.25"> <div className="px-docs_0.25">
<Link <Link
@@ -20,10 +21,13 @@ export const MenuItem = ({ item }: MenuItemProps) => {
"text-medusa-fg-base" "text-medusa-fg-base"
)} )}
href={item.link} href={item.link}
onClick={() => onClick?.(item)}
> >
{item.icon && (
<span className="text-medusa-fg-subtle mt-[2.5px] block"> <span className="text-medusa-fg-subtle mt-[2.5px] block">
{item.icon} {item.icon}
</span> </span>
)}
<span className="text-compact-small">{item.title}</span> <span className="text-compact-small">{item.title}</span>
</Link> </Link>
</div> </div>
@@ -8,9 +8,10 @@ import { MenuAction } from "./Action"
export type MenuProps = { export type MenuProps = {
items: MenuItemType[] items: MenuItemType[]
className?: string className?: string
itemsOnClick?: (item: MenuItemType) => void
} }
export const Menu = ({ items, className }: MenuProps) => { export const Menu = ({ items, className, itemsOnClick }: MenuProps) => {
return ( return (
<div <div
className={clsx( className={clsx(
@@ -21,9 +22,14 @@ export const Menu = ({ items, className }: MenuProps) => {
> >
{items.map((item, index) => ( {items.map((item, index) => (
<React.Fragment key={index}> <React.Fragment key={index}>
{item.type === "link" && <MenuItem item={item} />} {item.type === "link" && (
{item.type === "action" && <MenuAction item={item} />} <MenuItem item={item} onClick={itemsOnClick} />
)}
{item.type === "action" && (
<MenuAction item={item} onClick={itemsOnClick} />
)}
{item.type === "divider" && <MenuDivider />} {item.type === "divider" && <MenuDivider />}
{item.type === "custom" && item.content}
</React.Fragment> </React.Fragment>
))} ))}
</div> </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" "use client"
import React, { MouseEvent, useMemo } from "react" import React, { MouseEvent } from "react"
import clsx from "clsx" import { useSearch } from "@/providers"
import { useMobile, useSearch } from "@/providers" import { Button } from "@/components"
import { Button, Tooltip } from "@/components"
import { MagnifyingGlass } from "@medusajs/icons" import { MagnifyingGlass } from "@medusajs/icons"
import { useKeyboardShortcut } from "@/hooks" import { useKeyboardShortcut } from "@/hooks"
@@ -14,15 +13,8 @@ export type SearchModalOpenerProps = {
export const SearchModalOpener = ({ export const SearchModalOpener = ({
isLoading = false, isLoading = false,
className,
}: SearchModalOpenerProps) => { }: SearchModalOpenerProps) => {
const { isMobile } = useMobile()
const { setIsOpen } = useSearch() const { setIsOpen } = useSearch()
const isApple = useMemo(() => {
return typeof navigator !== "undefined"
? navigator.userAgent.toLowerCase().indexOf("mac") !== 0
: true
}, [])
useKeyboardShortcut({ useKeyboardShortcut({
shortcutKeys: ["k"], shortcutKeys: ["k"],
action: () => setIsOpen((prev) => !prev), action: () => setIsOpen((prev) => !prev),
@@ -46,29 +38,12 @@ export const SearchModalOpener = ({
} }
return ( return (
<>
{isMobile && (
<Button variant="transparent" onClick={handleOpen}>
<MagnifyingGlass className="text-medusa-fg-muted" />
</Button>
)}
{!isMobile && (
<Tooltip place="bottom" tooltipChildren="Ask or search">
<Button <Button
className={clsx( variant="transparent"
"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} onClick={handleOpen}
className="hidden sm:flex !p-[6.5px]"
> >
<MagnifyingGlass /> <MagnifyingGlass className="text-medusa-fg-subtle" />
<span>{isApple ? "⌘" : "Ctrl"}K</span>
</Button> </Button>
</Tooltip>
)}
</>
) )
} }
@@ -4,7 +4,6 @@ import React from "react"
import { SidebarChild } from "../Child" import { SidebarChild } from "../Child"
import { InteractiveSidebarItem } from "types" import { InteractiveSidebarItem } from "types"
import { SidebarTopMobileClose } from "./MobileClose" import { SidebarTopMobileClose } from "./MobileClose"
import { SidebarTopMedusaMenu } from "./MedusaMenu"
import { DottedSeparator } from "../../.." import { DottedSeparator } from "../../.."
export type SidebarTopProps = { export type SidebarTopProps = {
@@ -17,14 +16,12 @@ export const SidebarTop = React.forwardRef<HTMLDivElement, SidebarTopProps>(
<div className="pt-docs_0.25"> <div className="pt-docs_0.25">
<SidebarTopMobileClose /> <SidebarTopMobileClose />
<div ref={ref}> <div ref={ref}>
<SidebarTopMedusaMenu />
{parentItem && ( {parentItem && (
<> <>
<DottedSeparator />
<SidebarChild item={parentItem} /> <SidebarChild item={parentItem} />
<DottedSeparator wrapperClassName="!my-0" />
</> </>
)} )}
<DottedSeparator wrapperClassName="!my-0" />
</div> </div>
</div> </div>
) )
@@ -118,8 +118,8 @@ export const Sidebar = ({
}} }}
id="sidebar" id="sidebar"
> >
{/* MOBILE SIDEBAR */} {/* MOBILE SIDEBAR - keeping this in case we need it in the future */}
<div className={clsx("lg:hidden")}> {/* <div className={clsx("lg:hidden")}>
{!sidebarItems.mobile.length && !staticSidebarItems && ( {!sidebarItems.mobile.length && !staticSidebarItems && (
<Loading className="px-0" /> <Loading className="px-0" />
)} )}
@@ -131,8 +131,8 @@ export const Sidebar = ({
hasNextItems={index !== sidebarItems.default.length - 1} hasNextItems={index !== sidebarItems.default.length - 1}
/> />
))} ))}
<DottedSeparator /> {sidebarItems.mobile.length > 0 && <DottedSeparator />}
</div> </div> */}
{/* DESKTOP SIDEBAR */} {/* DESKTOP SIDEBAR */}
<div className="mt-docs_0.75 lg:mt-0"> <div className="mt-docs_0.75 lg:mt-0">
{!sidebarItems.default.length && !staticSidebarItems && ( {!sidebarItems.default.length && !staticSidebarItems && (
+81 -185
View File
@@ -1,195 +1,118 @@
import React from "react"
import { Badge } from "@/components"
import { OptionType } from "@/hooks" import { OptionType } from "@/hooks"
import { NavigationDropdownItem, SidebarItem } from "types" import { NavigationItem } 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"
export const GITHUB_ISSUES_PREFIX = `https://github.com/medusajs/medusa/issues/new?assignees=&labels=type%3A+docs&template=docs.yml` 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 GITHUB_UI_ISSUES_PREFIX = `https://github.com/medusajs/ui/issues/new?labels=documentation`
export const navDropdownItemsV2: NavigationDropdownItem[] = [ export const navDropdownItems: NavigationItem[] = [
{ {
type: "link", type: "link",
path: `/v2`, path: `/v2`,
icon: NavigationDropdownDocIcon, title: "Get Started",
title: "Documentation", project: "book",
}, },
{
type: "dropdown",
title: "Product",
children: [
{ {
type: "link", type: "link",
path: `/v2/resources/commerce-modules`,
icon: NavigationDropdownModulesIcon,
title: "Commerce Modules", title: "Commerce Modules",
link: "/v2/resources/commerce-modules",
}, },
{ {
type: "link", type: "link",
path: `/v2/resources`, title: "Architectural Modules",
icon: NavigationDropdownResourcesIcon, link: "/v2/resources/architectural-modules",
title: "Development Resources", },
],
},
{
type: "dropdown",
title: "Resources",
children: [
{
type: "link",
title: "Guides",
link: "/v2/resources",
useAsFallback: true,
}, },
{ {
type: "link", type: "link",
path: `/v2/api/store`, title: "Recipes",
icon: NavigationDropdownStoreIcon, link: "/v2/resources/recipes",
title: "Store API",
}, },
{ {
type: "link", type: "link",
path: `/v2/api/admin`, title: "UI Library",
icon: NavigationDropdownAdminIcon, link: "/ui",
},
{
type: "divider",
},
{
type: "link",
title: "Storefront Development",
link: "/v2/resources/storefront-development",
},
],
},
{
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: "dropdown",
title: "Reference",
children: [
{
type: "link",
title: "Admin API", title: "Admin API",
}, link: "/v2/api/admin",
{
type: "link",
path: `/ui`,
icon: NavigationDropdownUiIcon,
title: "UI",
},
{
type: "link",
path: `/`,
icon: NavigationDropdownDocV1Icon,
title: "Medusa v1",
},
]
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", type: "link",
title: "Store API", title: "Store API",
path: `/api/store`, link: "/v2/api/store",
loaded: true, },
isPathHref: true, {
type: "divider",
}, },
{ {
type: "link", type: "link",
title: "Admin API", title: "Workflows",
path: `/api/admin`, link: "/v2/resources/medusa-workflows-reference",
loaded: true,
isPathHref: true,
}, },
{ {
type: "link", type: "link",
title: "UI", title: "Data Model API",
path: `/ui`, link: "/v2/resources/references/data-model",
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[] = [ export const searchFilters: OptionType[] = [
{
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[] = [
{ {
value: "guides", value: "guides",
label: "Guides", label: "Guides",
@@ -206,36 +129,9 @@ export const searchFiltersV2: OptionType[] = [
value: "store-v2", value: "store-v2",
label: "Store API (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", value: "ui",
label: "UI", label: "Medusa UI",
}, },
// TODO add more filters
] ]
@@ -50,7 +50,8 @@ export const MainContentLayout = ({
"flex-col items-center", "flex-col items-center",
"h-full w-full", "h-full w-full",
"overflow-y-scroll overflow-x-hidden", "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 mainWrapperClasses
)} )}
id="main" id="main"
+1 -2
View File
@@ -1,7 +1,6 @@
import React from "react" import React from "react"
import clsx from "clsx" import clsx from "clsx"
import { RootProviders, Sidebar, SidebarProps } from "@/components" import { RootProviders, Sidebar, SidebarProps } from "@/components"
import { MobileNavigation } from "../components/MobileNavigation"
import { Toc } from "../components/Toc" import { Toc } from "../components/Toc"
import { MainContentLayout, MainContentLayoutProps } from "./main-content" import { MainContentLayout, MainContentLayoutProps } from "./main-content"
@@ -14,6 +13,7 @@ export type RootLayoutProps = {
showPagination?: boolean showPagination?: boolean
feedbackComponent?: React.ReactNode feedbackComponent?: React.ReactNode
editComponent?: React.ReactNode editComponent?: React.ReactNode
showBreadcrumbs?: boolean
} & MainContentLayoutProps } & MainContentLayoutProps
export const RootLayout = ({ export const RootLayout = ({
@@ -38,7 +38,6 @@ export const RootLayout = ({
> >
<RootProviders> <RootProviders>
<ProvidersComponent> <ProvidersComponent>
<MobileNavigation />
<Sidebar {...sidebarProps} /> <Sidebar {...sidebarProps} />
<div className={clsx("relative", "h-screen", "flex")}> <div className={clsx("relative", "h-screen", "flex")}>
<MainContentLayout {...mainProps} /> <MainContentLayout {...mainProps} />
+3 -1
View File
@@ -1,13 +1,14 @@
import React from "react" import React from "react"
import { RootLayout, RootLayoutProps } from "./root" import { RootLayout, RootLayoutProps } from "./root"
import clsx from "clsx" import clsx from "clsx"
import { Pagination } from ".." import { Breadcrumbs, Pagination } from ".."
export const TightLayout = ({ export const TightLayout = ({
children, children,
showPagination, showPagination,
feedbackComponent, feedbackComponent,
editComponent, editComponent,
showBreadcrumbs = true,
...props ...props
}: RootLayoutProps) => { }: RootLayoutProps) => {
return ( return (
@@ -21,6 +22,7 @@ export const TightLayout = ({
"px-docs_1 md:px-docs_4 lg:px-0" "px-docs_1 md:px-docs_4 lg:px-0"
)} )}
> >
{showBreadcrumbs && <Breadcrumbs />}
{children} {children}
{feedbackComponent} {feedbackComponent}
{showPagination && <Pagination />} {showPagination && <Pagination />}
+3 -1
View File
@@ -1,13 +1,14 @@
import React from "react" import React from "react"
import { RootLayout, RootLayoutProps } from "./root" import { RootLayout, RootLayoutProps } from "./root"
import clsx from "clsx" import clsx from "clsx"
import { Pagination } from ".." import { Breadcrumbs, Pagination } from ".."
export const WideLayout = ({ export const WideLayout = ({
children, children,
showPagination, showPagination,
feedbackComponent, feedbackComponent,
editComponent, editComponent,
showBreadcrumbs = true,
...props ...props
}: RootLayoutProps) => { }: RootLayoutProps) => {
return ( 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" "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} {children}
{feedbackComponent} {feedbackComponent}
{showPagination && <Pagination />} {showPagination && <Pagination />}
@@ -1,27 +1,24 @@
"use client" "use client"
import { usePathname } from "next/navigation"
import React, { createContext, useContext, useMemo } from "react" import React, { createContext, useContext, useMemo } from "react"
import { import { NavigationItem } from "types"
BreadcrumbOptions, import { useSiteConfig } from "../SiteConifg"
NavigationDropdownItem,
NavigationDropdownItemLink,
} from "types"
export type MainNavContext = { export type MainNavContext = {
navItems: NavigationDropdownItem[] navItems: NavigationItem[]
activeItem?: NavigationDropdownItemLink activeItemIndex?: number
activeItem?: NavigationItem
reportIssueLink: string reportIssueLink: string
editDate?: string editDate?: string
breadcrumbOptions: BreadcrumbOptions
} }
const MainNavContext = createContext<MainNavContext | null>(null) const MainNavContext = createContext<MainNavContext | null>(null)
export type MainNavProviderProps = { export type MainNavProviderProps = {
navItems: NavigationDropdownItem[] navItems: NavigationItem[]
reportIssueLink: string reportIssueLink: string
editDate?: string editDate?: string
breadcrumbOptions?: BreadcrumbOptions
children?: React.ReactNode children?: React.ReactNode
} }
@@ -30,26 +27,72 @@ export const MainNavProvider = ({
reportIssueLink, reportIssueLink,
children, children,
editDate, editDate,
breadcrumbOptions = {
showCategories: true,
},
}: MainNavProviderProps) => { }: MainNavProviderProps) => {
const activeItem = useMemo( const pathname = usePathname()
() => const { config } = useSiteConfig()
navItems.find(
(item) => item.type === "link" && item.isActive const baseUrl = `${config.baseUrl}${config.basePath}`
) as NavigationDropdownItemLink,
[navItems] 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 ( return (
<MainNavContext.Provider <MainNavContext.Provider
value={{ value={{
navItems, navItems,
activeItem, activeItemIndex,
reportIssueLink, reportIssueLink,
editDate, editDate,
breadcrumbOptions, activeItem,
}} }}
> >
{children} {children}
@@ -26,6 +26,13 @@ export const SiteConfigProvider = ({
default: [], default: [],
mobile: [], 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 { NavigationItem } from "types"
import { navDropdownItemsV1, navDropdownItemsV2 } from ".." import { navDropdownItems } from ".."
type Options = { type Options = {
basePath: string basePath: string
activePath: string
version?: "v1" | "v2"
} }
export function getNavDropdownItems({ export function getNavDropdownItems({ basePath }: Options): NavigationItem[] {
basePath, return navDropdownItems.map((item) => {
activePath, const newItem = {
version = "v1", ...item,
}: Options): NavigationDropdownItem[] { }
const items = version === "v2" ? navDropdownItemsV2 : navDropdownItemsV1
return items.map((item) => { if (newItem.type === "link") {
if (item.type === "divider") { newItem.path = `${basePath}${newItem.path}`
return item } else {
newItem.children = newItem.children.map((childItem) => {
if (childItem.type !== "link") {
return childItem
} }
return { return {
...item, ...childItem,
isActive: activePath === item.path, link: `${basePath}${childItem.link}`,
path: `${basePath}${item.path}`,
} }
}) })
} }
return newItem
})
}
-1
View File
@@ -5,7 +5,6 @@ export * from "./decode-str"
export * from "./dom-utils" export * from "./dom-utils"
export * from "./format-report-link" export * from "./format-report-link"
export * from "./get-link-with-base-path" export * from "./get-link-with-base-path"
export * from "./get-mobile-sidebar-items"
export * from "./get-navbar-items" export * from "./get-navbar-items"
export * from "./get-os-shortcut" export * from "./get-os-shortcut"
export * from "./get-scrolled-top" export * from "./get-scrolled-top"
@@ -191,23 +191,23 @@ module.exports = {
"elevation-card-rest": "elevation-card-rest":
"0px 0px 0px 1px rgba(0, 0, 0, 0.08), 0px 1px 2px -1px rgba(0, 0, 0, 0.08), 0px 2px 4px 0px rgba(0, 0, 0, 0.04)", "0px 0px 0px 1px rgba(0, 0, 0, 0.08), 0px 1px 2px -1px rgba(0, 0, 0, 0.08), 0px 2px 4px 0px rgba(0, 0, 0, 0.04)",
"elevation-card-rest-dark": "elevation-card-rest-dark":
"0px -1px 0px 0px rgba(255, 255, 255, 0.06), 0px 0px 0px 1px rgba(255, 255, 255, 0.06), 0px 0px 0px 1px rgba(39, 39, 42, 1), 0px 1px 2px 0px rgba(0, 0, 0, 0.32), 0px 2px 4px 0px rgba(0, 0, 0, 0.32)", "0px -1px 0px 0px rgba(255, 255, 255, 0.06), 0px 0px 0px 1px rgba(255, 255, 255, 0.06), 0px 0px 0px 1px #27272A, 0px 1px 2px 0px rgba(0, 0, 0, 0.32), 0px 2px 4px 0px rgba(0, 0, 0, 0.32)",
"elevation-card-hover": "elevation-card-hover":
"0px 0px 0px 1px rgba(0, 0, 0, 0.08), 0px 1px 2px -1px rgba(0, 0, 0, 0.08), 0px 2px 8px 0px rgba(0, 0, 0, 0.1)", "0px 0px 0px 1px rgba(0, 0, 0, 0.08), 0px 1px 2px -1px rgba(0, 0, 0, 0.08), 0px 2px 8px 0px rgba(0, 0, 0, 0.10)",
"elevation-card-hover-dark": "elevation-card-hover-dark":
"0px -1px 0px 0px rgba(255, 255, 255, 0.06), 0px 0px 0px 1px rgba(255, 255, 255, 0.06), 0px 0px 0px 1px rgba(39, 39, 42, 1), 0px 1px 4px 0px rgba(0, 0, 0, 0.48), 0px 2px 8px 0px rgba(0, 0, 0, 0.48)", "0px -1px 0px 0px rgba(255, 255, 255, 0.06), 0px 0px 0px 1px rgba(255, 255, 255, 0.06), 0px 0px 0px 1px #27272A, 0px 1px 4px 0px rgba(0, 0, 0, 0.48), 0px 2px 8px 0px rgba(0, 0, 0, 0.48)",
"elevation-tooltip": "elevation-tooltip":
"0px 0px 0px 1px rgba(0, 0, 0, 0.08), 0px 2px 4px 0px rgba(0, 0, 0, 0.08), 0px 4px 8px 0px rgba(0, 0, 0, 0.08)", "0px 0px 0px 1px rgba(0, 0, 0, 0.08), 0px 2px 4px 0px rgba(0, 0, 0, 0.08), 0px 4px 8px 0px rgba(0, 0, 0, 0.08)",
"elevation-tooltip-dark": "elevation-tooltip-dark":
"0px -1px 0px 0px rgba(255, 255, 255, 0.04), 0px 0px 0px 1px rgba(255, 255, 255, 0.1), 0px 2px 4px 0px rgba(0, 0, 0, 0.32), 0px 4px 8px 0px rgba(0, 0, 0, 0.32)", "0px -1px 0px 0px rgba(255, 255, 255, 0.04), 0px 0px 0px 1px rgba(255, 255, 255, 0.10), 0px 2px 4px 0px rgba(0, 0, 0, 0.32), 0px 4px 8px 0px rgba(0, 0, 0, 0.32)",
"elevation-flyout": "elevation-flyout":
"0px 0px 0px 1px rgba(0, 0, 0, 0.08), 0px 4px 8px 0px rgba(0, 0, 0, 0.08), 0px 8px 16px 0px rgba(0, 0, 0, 0.08)", "0px 0px 0px 1px rgba(0, 0, 0, 0.08), 0px 4px 8px 0px rgba(0, 0, 0, 0.08), 0px 8px 16px 0px rgba(0, 0, 0, 0.08)",
"elevation-flyout-dark": "elevation-flyout-dark":
"0px -1px 0px 0px rgba(255, 255, 255, 0.04), 0px 0px 0px 1px rgba(255, 255, 255, 0.1), 0px 4px 8px 0px rgba(0, 0, 0, 0.32), 0px 8px 16px 0px rgba(0, 0, 0, 0.32)", "0px -1px 0px 0px rgba(255, 255, 255, 0.04), 0px 0px 0px 1px rgba(255, 255, 255, 0.10), 0px 4px 8px 0px rgba(0, 0, 0, 0.32), 0px 8px 16px 0px rgba(0, 0, 0, 0.32)",
"elevation-modal": "elevation-modal":
"0px 0px 0px 1px rgba(255, 255, 255, 1) inset, 0px 0px 0px 1.5px rgba(228, 228, 231, 0.6) inset, 0px 0px 0px 1px rgba(0, 0, 0, 0.08), 0px 8px 16px 0px rgba(0, 0, 0, 0.08), 0px 16px 32px 0px rgba(0, 0, 0, 0.08)", "0px 0px 0px 1px #FFF inset, 0px 0px 0px 1.5px rgba(228, 228, 231, 0.60) inset, 0px 0px 0px 1px rgba(0, 0, 0, 0.08), 0px 8px 16px 0px rgba(0, 0, 0, 0.08), 0px 16px 32px 0px rgba(0, 0, 0, 0.08)",
"elevation-modal-dark": "elevation-modal-dark":
"0px 0px 0px 1px rgba(24, 24, 27, 1) inset, 0px 0px 0px 1.5px rgba(255, 255, 255, 0.06) inset, 0px -1px 0px 0px rgba(255, 255, 255, 0.04), 0px 0px 0px 1px rgba(255, 255, 255, 0.1), 0px 4px 8px 0px rgba(0, 0, 0, 0.32), 0px 8px 16px 0px rgba(0, 0, 0, 0.32)", "0px 0px 0px 1px #18181B inset, 0px 0px 0px 1.5px rgba(255, 255, 255, 0.06) inset, 0px -1px 0px 0px rgba(255, 255, 255, 0.04), 0px 0px 0px 1px rgba(255, 255, 255, 0.10), 0px 4px 8px 0px rgba(0, 0, 0, 0.32), 0px 8px 16px 0px rgba(0, 0, 0, 0.32)",
"button-neutral": "button-neutral":
"0px 1px 2px 0px rgba(0, 0, 0, 0.12), 0px 0px 0px 1px rgba(0, 0, 0, 0.08)", "0px 1px 2px 0px rgba(0, 0, 0, 0.12), 0px 0px 0px 1px rgba(0, 0, 0, 0.08)",
"button-neutral-dark": "button-neutral-dark":
@@ -234,7 +234,7 @@ module.exports = {
"0px -1px 0px 0px rgba(255, 255, 255, 0.12), 0px 0px 0px 1px rgba(255, 255, 255, 0.12), 0px 0px 0px 1px rgba(82, 82, 91, 1), 0px 0px 0px 2px rgba(24, 24, 27, 1), 0px 0px 0px 4px rgba(96, 165, 250, 0.8)", "0px -1px 0px 0px rgba(255, 255, 255, 0.12), 0px 0px 0px 1px rgba(255, 255, 255, 0.12), 0px 0px 0px 1px rgba(82, 82, 91, 1), 0px 0px 0px 2px rgba(24, 24, 27, 1), 0px 0px 0px 4px rgba(96, 165, 250, 0.8)",
"elevation-code-block": "elevation-code-block":
"0px 0px 0px 1px #18181B, 0px 0px 0px 1.5px rgba(255, 255, 255, 0.20)", "0px 0px 0px 1px #18181B inset, 0px 0px 0px 1.5px rgba(255, 255, 255, 0.20) inset",
"elevation-code-block-dark": "elevation-code-block-dark":
"0px -1px 0px 0px rgba(255, 255, 255, 0.06), 0px 0px 0px 1px rgba(255, 255, 255, 0.06), 0px 0px 0px 1px #27272A, 0px 1px 2px 0px rgba(0, 0, 0, 0.32), 0px 2px 4px 0px rgba(0, 0, 0, 0.32)", "0px -1px 0px 0px rgba(255, 255, 255, 0.06), 0px 0px 0px 1px rgba(255, 255, 255, 0.06), 0px 0px 0px 1px #27272A, 0px 1px 2px 0px rgba(0, 0, 0, 0.32), 0px 2px 4px 0px rgba(0, 0, 0, 0.32)",
active: "0px 0px 0px 3px #E1F0FF", active: "0px 0px 0px 3px #E1F0FF",
@@ -326,7 +326,7 @@ module.exports = {
h1: [ h1: [
"24px", "24px",
{ {
lineHeight: "36px", lineHeight: "125%",
fontWeight: "500", fontWeight: "500",
}, },
], ],
+9
View File
@@ -1,5 +1,9 @@
import { SidebarSectionItems } from "./sidebar.js" import { SidebarSectionItems } from "./sidebar.js"
export type BreadcrumbOptions = {
showCategories?: boolean
}
export declare type DocsConfig = { export declare type DocsConfig = {
titleSuffix?: string titleSuffix?: string
baseUrl: string baseUrl: string
@@ -7,4 +11,9 @@ export declare type DocsConfig = {
sidebar: SidebarSectionItems sidebar: SidebarSectionItems
filesBasePath?: string filesBasePath?: string
useNextLinks?: boolean useNextLinks?: boolean
project: {
title: string
key: string
}
breadcrumbOptions?: BreadcrumbOptions
} }
+1
View File
@@ -2,6 +2,7 @@ export * from "./api-testing.js"
export * from "./config.js" export * from "./config.js"
export * from "./general.js" export * from "./general.js"
export * from "./menu.js" export * from "./menu.js"
export * from "./navigation.js"
export * from "./navigation-dropdown.js" export * from "./navigation-dropdown.js"
export * from "./sidebar.js" export * from "./sidebar.js"
export * from "./toc.js" export * from "./toc.js"
+11 -2
View File
@@ -1,6 +1,6 @@
export type MenuItemLink = { export type MenuItemLink = {
type: "link" type: "link"
icon: React.ReactNode icon?: React.ReactNode
title: string title: string
link: string link: string
} }
@@ -17,4 +17,13 @@ export type MenuItemAction = {
action: () => void action: () => void
} }
export type MenuItem = MenuItemLink | MenuItemDivider | MenuItemAction export type MenuItemCustom = {
type: "custom"
content: React.ReactNode
}
export type MenuItem =
| MenuItemLink
| MenuItemDivider
| MenuItemAction
| MenuItemCustom
@@ -14,7 +14,3 @@ export type NavigationDropdownItem =
| { | {
type: "divider" type: "divider"
} }
export type BreadcrumbOptions = {
showCategories?: boolean
}
+20
View File
@@ -0,0 +1,20 @@
import { MenuItem } from "./menu.js"
export type NavigationItemDropdown = {
type: "dropdown"
title: string
children: (MenuItem & {
useAsFallback?: boolean
})[]
project?: string
}
export type NavigationItemLink = {
type: "link"
path: string
title: string
project?: string
useAsFallback?: boolean
}
export type NavigationItem = NavigationItemLink | NavigationItemDropdown