docs: redesign sidebar (#8408)

* initial changes

* redesign the sidebar + nav drawer

* changes to sidebar items

* finish up sidebar redesign

* support new sidebar in resources

* general fixes

* integrate in ui

* support api reference

* refactor

* integrate in user guide

* docs: fix build errors

* fix user guide build

* more refactoring

* added banner

* added bottom logo + icon

* fix up sidebar

* fix up paddings

* fix shadow bottom

* docs: add table of content (#8445)

* add toc types

* implement toc functionality

* finished toc redesign

* redesigned table of content

* mobile fixes

* truncate text in toc

* mobile fixes

* merge fixes

* implement redesign

* add hide sidebar

* add menu action item

* finish up hide sidebar design

* implement redesign in resources

* integrate in api reference

* integrate changes in ui

* fixes to api reference scrolling

* fix build error

* fix build errors

* fixes

* fixes to sidebar

* general fixes

* fix active category not closing

* fix long titles
This commit is contained in:
Shahed Nasser authored and GitHub committed 2024-08-15 12:13:13 +03:00
1 parent 4cb28531e5
commit b4f3b8a79d
157 files changed
+5080 -2010

No files matched your search

+1 -1
View File
@@ -15,7 +15,7 @@ const ReferencePage = async () => {
</h1>
<DividedLayout
mainContent={
<Section>
<Section checkActiveOnScroll={true}>
<h1 className="!text-h2 hidden lg:block">
Medusa V2 Admin API Reference
</h1>
+5 -2
View File
@@ -1,5 +1,4 @@
import "./globals.css"
import Navbar from "@/components/Navbar"
import Providers from "../providers"
import { WideLayout } from "docs-ui"
import { Inter, Roboto_Mono } from "next/font/google"
@@ -29,8 +28,12 @@ export default function RootLayout({
return (
<WideLayout
ProvidersComponent={Providers}
NavbarComponent={Navbar}
sidebarProps={{
expandItems: false,
}}
bodyClassName={clsx(inter.variable, robotoMono.variable)}
showToc={false}
showBanner={false}
>
{children}
</WideLayout>
+1 -1
View File
@@ -15,7 +15,7 @@ const ReferencePage = async () => {
</h1>
<DividedLayout
mainContent={
<Section>
<Section checkActiveOnScroll={true}>
<h1 className="!text-h2 hidden lg:block">
Medusa V2 Store API Reference
</h1>
@@ -1,73 +1,47 @@
"use client"
import { InView } from "react-intersection-observer"
import { isElmWindow, useScrollController, useSidebar } from "docs-ui"
import checkElementInViewport from "../../../utils/check-element-in-viewport"
import { useEffect, useMemo } from "react"
import { useScrollController, useSidebar } from "docs-ui"
import { useEffect, useMemo, useRef, useState } from "react"
import getSectionId from "../../../utils/get-section-id"
type H2Props = {
addToSidebar?: boolean
} & React.HTMLAttributes<HTMLHeadingElement>
type H2Props = React.HTMLAttributes<HTMLHeadingElement>
const H2 = ({ addToSidebar = true, children, ...props }: H2Props) => {
const { activePath, setActivePath, addItems } = useSidebar()
const { getScrolledTop, scrollableElement } = useScrollController()
const H2 = ({ children, ...props }: H2Props) => {
const headingRef = useRef<HTMLHeadingElement>(null)
const { activePath, addItems } = useSidebar()
const { scrollableElement, scrollToElement } = useScrollController()
const [scrolledFirstTime, setScrolledFirstTime] = useState(false)
const handleViewChange = (
inView: boolean,
entry: IntersectionObserverEntry
) => {
if (!addToSidebar) {
return
}
const heading = entry.target
if (
(inView ||
checkElementInViewport(heading.parentElement || heading, 40)) &&
getScrolledTop() !== 0 &&
activePath !== heading.id
) {
// can't use next router as it doesn't support
// changing url without scrolling
history.pushState({}, "", `#${heading.id}`)
setActivePath(heading.id)
}
}
const id = getSectionId([children as string])
const id = useMemo(() => getSectionId([children as string]), [children])
useEffect(() => {
if (id === (activePath || location.hash.replace("#", ""))) {
const elm = document.getElementById(id)
elm?.scrollIntoView()
if (!scrollableElement || !headingRef.current || scrolledFirstTime) {
return
}
if (id === (activePath || location.hash.replace("#", ""))) {
scrollToElement(
(headingRef.current.offsetParent as HTMLElement) || headingRef.current
)
}
setScrolledFirstTime(scrolledFirstTime)
}, [scrollableElement, headingRef, id])
useEffect(() => {
addItems([
{
type: "link",
path: `${id}`,
title: children as string,
loaded: true,
},
])
}, [])
const root = useMemo(() => {
return isElmWindow(scrollableElement) ? document.body : scrollableElement
}, [scrollableElement])
}, [id])
return (
<InView
as="h2"
threshold={0.4}
skip={!addToSidebar}
initialInView={false}
{...props}
onChange={handleViewChange}
id={id}
root={root}
>
<h2 {...props} id={id} ref={headingRef}>
{children}
</InView>
</h2>
)
}
@@ -14,9 +14,7 @@ const getCustomComponents = (scope?: ScopeType): MDXComponents => {
...UiMDXComponents,
Security: () => <Security specs={scope?.specs} />,
a: Link,
h2: (props: React.HTMLAttributes<HTMLHeadingElement>) => (
<H2 addToSidebar={scope?.addToSidebar} {...props} />
),
h2: (props: React.HTMLAttributes<HTMLHeadingElement>) => <H2 {...props} />,
}
}
@@ -1,28 +0,0 @@
"use client"
import { Button, useModal, usePageLoading } from "docs-ui"
import DetailedFeedback from "../../DetailedFeedback"
const FeedbackModal = () => {
const { setModalProps } = useModal()
const { isLoading } = usePageLoading()
const openModal = () => {
if (isLoading) {
return
}
setModalProps({
title: "Send your Feedback",
children: <DetailedFeedback />,
contentClassName: "lg:!min-h-auto !p-0",
})
}
return (
<Button onClick={openModal} variant="secondary">
Feedback
</Button>
)
}
export default FeedbackModal
@@ -1,50 +0,0 @@
"use client"
import {
Navbar as UiNavbar,
getNavbarItems,
usePageLoading,
useSidebar,
} from "docs-ui"
import FeedbackModal from "./FeedbackModal"
import { useMemo } from "react"
import { config } from "../../config"
import { usePathname } from "next/navigation"
import VersionSwitcher from "../VersionSwitcher"
import basePathUrl from "../../utils/base-path-url"
const Navbar = () => {
const { setMobileSidebarOpen, mobileSidebarOpen } = useSidebar()
const pathname = usePathname()
const { isLoading } = usePageLoading()
const navbarItems = useMemo(
() =>
getNavbarItems({
basePath: config.baseUrl,
activePath: basePathUrl(pathname),
version: "v2",
}),
[pathname]
)
return (
<UiNavbar
logo={{
light: basePathUrl("/images/logo-icon.png"),
dark: basePathUrl("/images/logo-icon-dark.png"),
}}
items={navbarItems}
mobileMenuButton={{
setMobileSidebarOpen,
mobileSidebarOpen,
}}
additionalActionsBefore={<VersionSwitcher />}
additionalActionsAfter={<FeedbackModal />}
showSearchOpener
isLoading={isLoading}
/>
)
}
export default Navbar
@@ -1,14 +1,25 @@
"use client"
import clsx from "clsx"
import { useActiveOnScroll, useSidebar } from "docs-ui"
import { useEffect, useRef } from "react"
export type SectionProps = {
addToSidebar?: boolean
checkActiveOnScroll?: boolean
} & React.AllHTMLAttributes<HTMLDivElement>
const Section = ({ children, className }: SectionProps) => {
const Section = ({
children,
className,
checkActiveOnScroll = false,
}: SectionProps) => {
const sectionRef = useRef<HTMLDivElement>(null)
const { activeItemId } = useActiveOnScroll({
rootElm: sectionRef.current || undefined,
enable: checkActiveOnScroll,
useDefaultIfNoActive: false,
})
const { setActivePath } = useSidebar()
useEffect(() => {
if ("scrollRestoration" in history) {
@@ -17,6 +28,13 @@ const Section = ({ children, className }: SectionProps) => {
}
}, [])
useEffect(() => {
if (activeItemId.length) {
history.pushState({}, "", `#${activeItemId}`)
setActivePath(activeItemId)
}
}, [activeItemId])
return (
<div
ref={sectionRef}
@@ -13,6 +13,7 @@ import TagsOperationDescriptionSection from "./DescriptionSection"
import DividedLayout from "@/layouts/Divided"
import { useLoading } from "@/providers/loading"
import SectionDivider from "../../Section/Divider"
import checkElementInViewport from "../../../utils/check-element-in-viewport"
const TagOperationCodeSection = dynamic<TagOperationCodeSectionProps>(
async () => import("./CodeSection")
@@ -40,7 +41,7 @@ const TagOperation = ({
)
const nodeRef = useRef<Element | null>(null)
const { loading, removeLoading } = useLoading()
const { scrollableElement } = useScrollController()
const { scrollableElement, scrollToTop } = useScrollController()
const root = useMemo(() => {
return isElmWindow(scrollableElement) ? document.body : scrollableElement
}, [scrollableElement])
@@ -75,24 +76,28 @@ const TagOperation = ({
[ref]
)
useEffect(() => {
const enableShow = () => {
setShow(true)
const scrollIntoView = useCallback(() => {
if (nodeRef.current && !checkElementInViewport(nodeRef.current, 10)) {
const elm = nodeRef.current as HTMLElement
scrollToTop(
elm.offsetTop + (elm.offsetParent as HTMLElement)?.offsetTop,
0
)
}
setShow(true)
}, [scrollToTop, nodeRef])
useEffect(() => {
if (nodeRef && nodeRef.current) {
removeLoading()
const currentHash = location.hash.replace("#", "")
if (currentHash === path) {
setTimeout(() => {
nodeRef.current?.scrollIntoView()
enableShow()
}, 100)
setTimeout(scrollIntoView, 100)
} else if (currentHash.split("_")[0] === path.split("_")[0]) {
enableShow()
setShow(true)
}
}
}, [nodeRef, path])
}, [nodeRef, path, scrollIntoView])
return (
<div
@@ -14,7 +14,7 @@ import { useBaseSpecs } from "@/providers/base-specs"
import getTagChildSidebarItems from "@/utils/get-tag-child-sidebar-items"
import { useLoading } from "@/providers/loading"
import DividedLoading from "@/components/DividedLoading"
import { SidebarItemSections, SidebarItemType } from "types"
import { SidebarItemSections, SidebarItem, SidebarItemCategory } from "types"
import basePathUrl from "../../../utils/base-path-url"
const TagOperation = dynamic<TagOperationProps>(
@@ -56,16 +56,17 @@ const TagPaths = ({ tag, className }: TagPathsProps) => {
useEffect(() => {
if (paths) {
const parentItem = findItemInSection(
items[SidebarItemSections.BOTTOM],
{ path: tagSlugName },
items[SidebarItemSections.DEFAULT],
{ title: tag.name },
false
)
const pathItems: SidebarItemType[] = getTagChildSidebarItems(paths)
) as SidebarItemCategory
const pathItems: SidebarItem[] = getTagChildSidebarItems(paths)
if ((parentItem?.children?.length || 0) < pathItems.length) {
addItems(pathItems, {
section: SidebarItemSections.BOTTOM,
section: SidebarItemSections.DEFAULT,
parent: {
path: tagSlugName,
title: tag.name,
path: "",
changeLoaded: true,
},
})
@@ -40,7 +40,7 @@ const TagSectionSchema = ({ schema, tagName }: TagSectionSchemaProps) => {
},
})
const { scrollableElement } = useScrollController()
const { scrollableElement, scrollToElement } = useScrollController()
const root = useMemo(() => {
return isElmWindow(scrollableElement) ? document.body : scrollableElement
}, [scrollableElement])
@@ -49,6 +49,7 @@ const TagSectionSchema = ({ schema, tagName }: TagSectionSchemaProps) => {
addItems(
[
{
type: "link",
path: schemaSlug,
title: `${formattedName} Object`,
additionalElms: <Badge variant="neutral">Schema</Badge>,
@@ -56,8 +57,9 @@ const TagSectionSchema = ({ schema, tagName }: TagSectionSchemaProps) => {
},
],
{
section: SidebarItemSections.BOTTOM,
section: SidebarItemSections.DEFAULT,
parent: {
title: tagName,
path: tagSlugName,
changeLoaded: true,
},
@@ -69,12 +71,12 @@ const TagSectionSchema = ({ schema, tagName }: TagSectionSchemaProps) => {
useEffect(() => {
if (schemaSlug === (activePath || location.hash.replace("#", ""))) {
const elm = document.getElementById(schemaSlug)
elm?.scrollIntoView({
block: "center",
})
const elm = document.getElementById(schemaSlug) as HTMLElement
if (!checkElementInViewport(elm, 40)) {
scrollToElement(elm)
}
}
}, [])
}, [activePath, schemaSlug])
const handleViewChange = (
inView: boolean,
@@ -26,6 +26,7 @@ import { SchemaObject, TagObject } from "@/types/openapi"
import useSWR from "swr"
import { TagSectionSchemaProps } from "./Schema"
import basePathUrl from "../../../utils/base-path-url"
import checkElementInViewport from "../../../utils/check-element-in-viewport"
export type TagSectionProps = {
tag: TagObject
@@ -52,7 +53,7 @@ const TagSection = ({ tag }: TagSectionProps) => {
const slugTagName = useMemo(() => getSectionId([tag.name]), [tag])
const { area } = useArea()
const pathname = usePathname()
const { scrollableElement } = useScrollController()
const { scrollableElement, scrollToElement } = useScrollController()
const { data } = useSWR<{
schema: SchemaObject
}>(
@@ -96,8 +97,10 @@ const TagSection = ({ tag }: TagSectionProps) => {
if (activePath && activePath.includes(slugTagName)) {
const tagName = activePath.split("_")
if (tagName.length === 1 && tagName[0] === slugTagName) {
const elm = document.getElementById(tagName[0]) as Element
elm?.scrollIntoView()
const elm = document.getElementById(tagName[0])
if (elm && !checkElementInViewport(elm, 10)) {
scrollToElement(elm)
}
} else if (tagName.length > 1 && tagName[0] === slugTagName) {
setLoadPaths(true)
}
@@ -11,7 +11,7 @@ import { swrFetcher, useSidebar } from "docs-ui"
import getSectionId from "@/utils/get-section-id"
import { ExpandedDocument } from "@/types/openapi"
import getTagChildSidebarItems from "@/utils/get-tag-child-sidebar-items"
import { SidebarItemSections } from "types"
import { SidebarItem, SidebarItemSections } from "types"
import basePathUrl from "../../utils/base-path-url"
const TagSection = dynamic<TagSectionProps>(
@@ -31,7 +31,7 @@ const Tags = () => {
const [loadData, setLoadData] = useState<boolean>(false)
const [expand, setExpand] = useState<string>("")
const { baseSpecs, setBaseSpecs } = useBaseSpecs()
const { addItems } = useSidebar()
const { addItems, setActivePath } = useSidebar()
const { area, prevArea } = useArea()
const { data } = useSWR<ExpandedDocument>(
@@ -65,30 +65,42 @@ const Tags = () => {
if (baseSpecs) {
if (prevArea !== area) {
setBaseSpecs(null)
setLoadData(true)
return
}
addItems(
baseSpecs.tags?.map((tag) => {
const itemsToAdd: SidebarItem[] = [
{
type: "separator",
},
]
if (baseSpecs.tags) {
baseSpecs.tags.forEach((tag) => {
const tagPathName = getSectionId([tag.name.toLowerCase()])
const childItems =
baseSpecs.expandedTags &&
Object.hasOwn(baseSpecs.expandedTags, tagPathName)
? getTagChildSidebarItems(baseSpecs.expandedTags[tagPathName])
: []
return {
path: tagPathName,
itemsToAdd.push({
type: "category",
title: tag.name,
children: childItems,
loaded: childItems.length > 0,
}
}) || [],
{
section: SidebarItemSections.BOTTOM,
}
)
onOpen: () => {
history.pushState({}, "", `#${tagPathName}`)
setActivePath(tagPathName)
},
})
})
}
addItems(itemsToAdd, {
section: SidebarItemSections.DEFAULT,
})
}
}, [baseSpecs, addItems])
}, [baseSpecs, prevArea, area])
return (
<>
+2 -2
View File
@@ -8,14 +8,14 @@ export const config: DocsConfig = {
basePath: process.env.NEXT_PUBLIC_BASE_PATH,
// sidebar is auto generated
sidebar: {
top: [
default: [
{
type: "link",
title: "Introduction",
path: "",
loaded: true,
},
],
bottom: [],
mobile: getMobileSidebarItems({
baseUrl,
version: "v2",
+6 -3
View File
@@ -13,6 +13,7 @@ import BaseSpecsProvider from "./base-specs"
import SidebarProvider from "./sidebar"
import SearchProvider from "./search"
import { config } from "../config"
import { MainNavProvider } from "./main-nav"
type ProvidersProps = {
children?: React.ReactNode
@@ -28,9 +29,11 @@ const Providers = ({ children }: ProvidersProps) => {
<BaseSpecsProvider>
<ScrollControllerProvider scrollableSelector="#main">
<SidebarProvider>
<SearchProvider>
<MobileProvider>{children}</MobileProvider>
</SearchProvider>
<MainNavProvider>
<SearchProvider>
<MobileProvider>{children}</MobileProvider>
</SearchProvider>
</MainNavProvider>
</SidebarProvider>
</ScrollControllerProvider>
</BaseSpecsProvider>
@@ -0,0 +1,48 @@
"use client"
import {
formatReportLink,
getNavDropdownItems,
MainNavProvider as UiMainNavProvider,
useIsBrowser,
} from "docs-ui"
import { useMemo } from "react"
import { config } from "../config"
import { usePathname } from "next/navigation"
import basePathUrl from "../utils/base-path-url"
type MainNavProviderProps = {
children?: React.ReactNode
}
export const MainNavProvider = ({ children }: MainNavProviderProps) => {
const isBrowser = useIsBrowser()
const pathname = usePathname()
const navigationDropdownItems = useMemo(
() =>
getNavDropdownItems({
basePath: config.baseUrl,
activePath: basePathUrl(pathname),
version: "v2",
}),
[pathname]
)
const reportLink = useMemo(
() =>
formatReportLink(
config.titleSuffix || "",
isBrowser ? document.title : ""
),
[isBrowser]
)
return (
<UiMainNavProvider
navItems={navigationDropdownItems}
reportIssueLink={reportLink}
>
{children}
</UiMainNavProvider>
)
}
@@ -3,6 +3,7 @@
import { createContext, useEffect } from "react"
import { capitalize, useSidebar } from "docs-ui"
import { useArea } from "./area"
import { SidebarItemLink } from "types"
const PageTitleContext = createContext(null)
@@ -25,7 +26,9 @@ const PageTitleProvider = ({ children }: PageTitleProviderProps) => {
document.title = `${activeItem?.title} - ${titleSuffix}`
} else {
// find the child that matches the active path
const item = activeItem?.children?.find((i) => i.path === activePath)
const item = activeItem?.children?.find(
(i) => i.type === "link" && i.path === activePath
) as SidebarItemLink
if (item) {
document.title = `${item.title} - ${titleSuffix}`
}
+5 -4
View File
@@ -1,4 +1,5 @@
"use client"
import {
SidebarProvider as UiSidebarProvider,
usePageLoading,
@@ -6,8 +7,8 @@ import {
useScrollController,
} from "docs-ui"
import { config } from "../config"
import { usePathname } from "next/navigation"
import { useCallback } from "react"
import { usePathname } from "next/navigation"
type SidebarProviderProps = {
children?: React.ReactNode
@@ -17,11 +18,11 @@ const SidebarProvider = ({ children }: SidebarProviderProps) => {
const { isLoading, setIsLoading } = usePageLoading()
const { scrollableElement } = useScrollController()
const pathname = usePathname()
const prevPathname = usePrevious(pathname)
const prevPathName = usePrevious(pathname)
const resetOnCondition = useCallback(
() => prevPathname !== undefined && prevPathname !== pathname,
[pathname, prevPathname]
() => prevPathName !== undefined && pathname !== prevPathName,
[pathname, prevPathName]
)
return (
@@ -1,5 +1,5 @@
import { getLinkWithBasePath } from "docs-ui"
export default function basePathUrl(path: string) {
export default function basePathUrl(path = "") {
return getLinkWithBasePath(path, process.env.NEXT_PUBLIC_BASE_PATH)
}
@@ -4,7 +4,7 @@ export default function checkElementInViewport(
height?: number
) {
const rect = element.getBoundingClientRect()
const windowHeight =
const windowHeight: number | undefined =
height || window.innerHeight || document.documentElement.clientHeight
return !(
@@ -1,4 +1,4 @@
import type { SidebarItemType } from "types"
import type { SidebarItem } from "types"
import type { Operation, PathsObject } from "@/types/openapi"
import type { OpenAPIV3 } from "openapi-types"
import dynamic from "next/dynamic"
@@ -11,13 +11,14 @@ const MethodLabel = dynamic<MethodLabelProps>(
export default function getTagChildSidebarItems(
paths: PathsObject
): SidebarItemType[] {
const items: SidebarItemType[] = []
): SidebarItem[] {
const items: SidebarItem[] = []
Object.entries(paths).forEach(([, operations]) => {
Object.entries(operations).map(([method, operation]) => {
const definedOperation = operation as Operation
const definedMethod = method as OpenAPIV3.HttpMethods
items.push({
type: "link",
path: getSectionId([
...(definedOperation.tags || []),
definedOperation.operationId,
+1 -5
View File
@@ -1,10 +1,8 @@
import type { Metadata } from "next"
import { Inter, Roboto_Mono } from "next/font/google"
import Navbar from "@/components/Navbar"
import Providers from "@/providers"
import "./globals.css"
import { Bannerv2, TightLayout } from "docs-ui"
import { TightLayout } from "docs-ui"
import { config } from "@/config"
import clsx from "clsx"
import Feedback from "@/components/Feedback"
@@ -40,10 +38,8 @@ export default function RootLayout({
return (
<TightLayout
ProvidersComponent={Providers}
NavbarComponent={Navbar}
sidebarProps={{
expandItems: true,
banner: <Bannerv2 />,
}}
showPagination={true}
bodyClassName={clsx(inter.variable, robotoMono.variable)}
-39
View File
@@ -1,39 +0,0 @@
"use client"
import { Navbar as UiNavbar, getNavbarItems } from "docs-ui"
import { useSidebar } from "docs-ui"
import { useMemo } from "react"
import { config } from "../../config"
import { basePathUrl } from "../../utils/base-path-url"
const Navbar = () => {
const { setMobileSidebarOpen, mobileSidebarOpen } = useSidebar()
const navbarItems = useMemo(
() =>
getNavbarItems({
basePath: config.baseUrl,
activePath: basePathUrl(),
version: "v2",
}),
[]
)
return (
<UiNavbar
logo={{
light: basePathUrl("/images/logo-icon.png"),
dark: basePathUrl("/images/logo-icon-dark.png"),
}}
items={navbarItems}
mobileMenuButton={{
setMobileSidebarOpen,
mobileSidebarOpen,
}}
isLoading={false}
showSearchOpener
/>
)
}
export default Navbar
+7 -5
View File
@@ -1,17 +1,20 @@
import { Badge, getMobileSidebarItems } from "docs-ui"
import type { SidebarConfig, SidebarItemType } from "@/types"
import type { SidebarConfig, SidebarItem } from "@/types"
import { sidebar } from "../sidebar.mjs"
const soonBadge = <Badge variant="blue">Soon</Badge>
const normalizeSidebarItems = (items: SidebarItemType[]) =>
const normalizeSidebarItems = (items: SidebarItem[]) =>
items.map((item) => {
if (item.type === "separator") {
return item
}
if (item.isSoon) {
item.additionalElms = soonBadge
}
if (item.children) {
item.children = normalizeSidebarItems(item.children as SidebarItemType[])
item.children = normalizeSidebarItems(item.children as SidebarItem[])
}
return item
@@ -19,8 +22,7 @@ const normalizeSidebarItems = (items: SidebarItemType[]) =>
export const sidebarConfig = (baseUrl: string): SidebarConfig => {
return {
top: normalizeSidebarItems(sidebar),
bottom: [],
default: normalizeSidebarItems(sidebar),
mobile: getMobileSidebarItems({
baseUrl,
version: "v2",
+13 -10
View File
@@ -16,6 +16,7 @@ import {
import SidebarProvider from "./sidebar"
import SearchProvider from "./search"
import { config } from "../config"
import { MainNavProvider } from "./main-nav"
type ProvidersProps = {
children?: React.ReactNode
@@ -33,16 +34,18 @@ const Providers = ({ children }: ProvidersProps) => {
<ScrollControllerProvider scrollableSelector="#main">
<SidebarProvider>
<PaginationProvider>
<SearchProvider>
<HooksLoader
options={{
pageScrollManager: true,
currentLearningPath: true,
}}
>
{children}
</HooksLoader>
</SearchProvider>
<MainNavProvider>
<SearchProvider>
<HooksLoader
options={{
pageScrollManager: true,
currentLearningPath: true,
}}
>
{children}
</HooksLoader>
</SearchProvider>
</MainNavProvider>
</PaginationProvider>
</SidebarProvider>
</ScrollControllerProvider>
+46
View File
@@ -0,0 +1,46 @@
"use client"
import {
formatReportLink,
getNavDropdownItems,
MainNavProvider as UiMainNavProvider,
useIsBrowser,
} from "docs-ui"
import { useMemo } from "react"
import { config } from "../config"
import { basePathUrl } from "../utils/base-path-url"
type MainNavProviderProps = {
children?: React.ReactNode
}
export const MainNavProvider = ({ children }: MainNavProviderProps) => {
const isBrowser = useIsBrowser()
const navigationDropdownItems = useMemo(
() =>
getNavDropdownItems({
basePath: config.baseUrl,
activePath: basePathUrl(),
version: "v2",
}),
[]
)
const reportLink = useMemo(
() =>
formatReportLink(
config.titleSuffix || "",
isBrowser ? document.title : ""
),
[isBrowser]
)
return (
<UiMainNavProvider
navItems={navigationDropdownItems}
reportIssueLink={reportLink}
>
{children}
</UiMainNavProvider>
)
}
+1 -1
View File
@@ -1,4 +1,5 @@
"use client"
import {
SidebarProvider as UiSidebarProvider,
useScrollController,
@@ -20,7 +21,6 @@ const SidebarProvider = ({ children }: SidebarProviderProps) => {
initialItems={config.sidebar}
staticSidebarItems={true}
disableActiveTransition={true}
noTitleStyling={true}
>
{children}
</UiSidebarProvider>
+75 -3
View File
@@ -1,183 +1,226 @@
import numberSidebarItems from "./utils/number-sidebar-items.mjs"
import { sidebarAttachHrefCommonOptions } from "./utils/sidebar-attach-common-options.mjs"
/** @type {import('@/types').SidebarItemType[]} */
export const sidebar = sidebarAttachHrefCommonOptions(
numberSidebarItems([
/** @type {import('@/types').SidebarItem[]} */
export const sidebar = numberSidebarItems(
sidebarAttachHrefCommonOptions([
{
type: "link",
path: "/",
title: "Introduction",
},
{
type: "link",
path: "/first-customizations",
title: "Your First Customizations",
},
{
type: "link",
path: "/basics",
title: "The Basics",
children: [
{
type: "link",
path: "/basics/project-directories-files",
title: "Project Directories and Files",
},
{
type: "link",
path: "/basics/medusa-container",
title: "Medusa Container",
},
{
type: "link",
path: "/basics/api-routes",
title: "API Routes",
},
{
type: "link",
path: "/basics/modules-and-services",
title: "Modules and Services",
},
{
type: "link",
path: "/basics/commerce-modules",
title: "Commerce Modules",
},
{
type: "link",
path: "/basics/modules-directory-structure",
title: "Modules Directory Structure",
},
{
type: "link",
path: "/basics/data-models",
title: "Data Models",
},
{
type: "link",
path: "/basics/loaders",
title: "Loaders",
},
{
type: "link",
path: "/basics/events-and-subscribers",
title: "Events and Subscribers",
},
{
type: "link",
path: "/basics/scheduled-jobs",
title: "Scheduled Jobs",
},
{
type: "link",
path: "/basics/workflows",
title: "Workflows",
},
{
type: "link",
path: "/basics/admin-customizations",
title: "Admin Customizations",
},
],
},
{
type: "link",
path: "/advanced-development",
title: "Advanced Development",
children: [
{
type: "sub-category",
title: "API Routes",
children: [
{
type: "link",
path: "/advanced-development/api-routes/http-methods",
title: "HTTP Methods",
},
{
type: "link",
path: "/advanced-development/api-routes/parameters",
title: "Parameters",
},
{
type: "link",
path: "/advanced-development/api-routes/middlewares",
title: "Middlewares",
},
{
type: "link",
path: "/advanced-development/api-routes/protected-routes",
title: "Protected Routes",
},
{
type: "link",
path: "/advanced-development/api-routes/cors",
title: "Handling CORS",
},
],
},
{
type: "sub-category",
title: "Modules",
children: [
{
type: "link",
path: "/advanced-development/modules/container",
title: "Module's Container",
},
{
type: "link",
path: "/advanced-development/modules/service-factory",
title: "Service Factory",
},
{
type: "link",
path: "/advanced-development/modules/isolation",
title: "Module Isolation",
},
{
type: "link",
path: "/advanced-development/modules/module-links",
title: "Module Links",
},
{
type: "link",
path: "/advanced-development/modules/module-link-directions",
title: "Module Link Direction",
},
{
type: "link",
path: "/advanced-development/modules/remote-link",
title: "Remote Link",
},
{
type: "link",
path: "/advanced-development/modules/remote-query",
title: "Remote Query",
},
{
type: "link",
path: "/advanced-development/modules/options",
title: "Module Options",
},
],
},
{
type: "link",
path: "/advanced-development/data-models",
title: "Data Models",
children: [
{
type: "link",
path: "/advanced-development/data-models/property-types",
title: "Property Types",
},
{
type: "link",
path: "/advanced-development/data-models/primary-key",
title: "Primary Key",
},
{
type: "link",
path: "/advanced-development/data-models/default-properties",
title: "Default Properties",
},
{
type: "link",
path: "/advanced-development/data-models/configure-properties",
title: "Configure Properties",
},
{
type: "link",
path: "/advanced-development/data-models/relationships",
title: "Relationships",
},
{
type: "link",
path: "/advanced-development/data-models/manage-relationships",
title: "Manage Relationships",
},
{
type: "link",
path: "/advanced-development/data-models/index",
title: "Index",
},
{
type: "link",
path: "/advanced-development/data-models/searchable-property",
title: "Searchable Property",
},
{
type: "link",
path: "/advanced-development/data-models/write-migration",
title: "Write Migration",
},
],
},
{
type: "sub-category",
title: "Events and Subscribers",
children: [
{
type: "link",
path: "/advanced-development/events-and-subscribers/data-payload",
title: "Events Data Payload",
},
@@ -188,84 +231,104 @@ export const sidebar = sidebarAttachHrefCommonOptions(
],
},
{
type: "sub-category",
title: "Scheduled Jobs",
children: [
{
type: "link",
path: "/advanced-development/scheduled-jobs/execution-number",
title: "Execution Number",
},
],
},
{
type: "sub-category",
title: "Workflows",
children: [
{
type: "link",
path: "/advanced-development/workflows/constructor-constraints",
title: "Workflow Constraints",
},
{
type: "link",
path: "/advanced-development/workflows/conditions",
title: "Conditions in Workflows",
},
{
type: "link",
path: "/advanced-development/workflows/compensation-function",
title: "Compensation Function",
},
{
type: "link",
path: "/advanced-development/workflows/workflow-hooks",
title: "Workflow Hooks",
},
{
type: "link",
path: "/advanced-development/workflows/add-workflow-hook",
title: "Expose a Hook",
},
{
type: "link",
path: "/advanced-development/workflows/access-workflow-errors",
title: "Access Workflow Errors",
},
{
type: "link",
path: "/advanced-development/workflows/retry-failed-steps",
title: "Retry Failed Steps",
},
{
type: "link",
path: "/advanced-development/workflows/parallel-steps",
title: "Run Steps in Parallel",
},
{
type: "link",
path: "/advanced-development/workflows/workflow-timeout",
title: "Workflow Timeout",
},
{
type: "link",
path: "/advanced-development/workflows/long-running-workflow",
title: "Long-Running Workflow",
},
{
type: "link",
path: "/advanced-development/workflows/execute-another-workflow",
title: "Execute Another Workflow",
},
{
type: "link",
path: "/advanced-development/workflows/advanced-example",
title: "Example: Advanced Workflow",
},
],
},
{
type: "link",
path: "/advanced-development/custom-cli-scripts",
title: "Custom CLI Scripts",
},
{
type: "link",
path: "/advanced-development/admin",
title: "Admin Development",
children: [
{
type: "link",
path: "/advanced-development/admin/widgets",
title: "Admin Widgets",
},
{
type: "link",
path: "/advanced-development/admin/ui-routes",
title: "Admin UI Routes",
},
{
type: "link",
path: "/advanced-development/admin/tips",
title: "Tips",
},
@@ -274,42 +337,51 @@ export const sidebar = sidebarAttachHrefCommonOptions(
],
},
{
type: "link",
path: "/storefront-development",
title: "Storefront Development",
children: [
{
type: "link",
path: "/storefront-development/nextjs-starter",
title: "Next.js Starter",
},
],
},
{
type: "link",
path: "/architectural-modules",
title: "Architectural Modules",
},
{
type: "link",
path: "/debugging-and-testing",
title: "Debugging and Testing",
children: [
{
type: "link",
path: "/debugging-and-testing/logging",
title: "Logging",
},
{
type: "link",
path: "/debugging-and-testing/tools",
title: "Tools",
},
],
},
{
type: "link",
path: "/deployment",
title: "Deployment",
},
{
type: "link",
path: "/more-resources",
title: "More Resources",
},
{
type: "link",
path: "/cheatsheet",
title: "Cheat Sheet",
},
+3 -6
View File
@@ -1,11 +1,8 @@
import {
SidebarSectionItemsType,
SidebarItemType as UiSidebarItemType,
} from "docs-ui"
import { SidebarSectionItems, SidebarItem as SidebarItemType } from "types"
export declare type SidebarItemType = UiSidebarItemType & {
export declare type SidebarItem = SidebarItemType & {
isSoon: boolean
number?: string
}
export declare type SidebarConfig = SidebarSectionItemsType
export declare type SidebarConfig = SidebarSectionItems
+34 -3
View File
@@ -1,14 +1,34 @@
/**
*
* @param {import("@/types").SidebarItemType[]} sidebarItems - The items to add numbers to their titles
* @param {import("@/types").SidebarItem[]} sidebarItems - The items to add numbers to their titles
* @param {number[]} numbering - The current numbering level
* @returns {import("@/types").SidebarItemType[]} The modified sidebar items
* @returns {import("@/types").SidebarItem[]} The modified sidebar items
*/
export default function numberSidebarItems(sidebarItems, numbering = [1]) {
// TODO generate chapter titles
if (!numbering.length) {
numbering.push(1)
}
const isTopItems = numbering.length === 1
/** @type {import("@/types").SidebarItem[]} */
const numberedItems = []
/** @type {import("@/types").SidebarItem | undefined} */
let parentItem
sidebarItems.forEach((item) => {
if (item.type === "separator") {
;(parentItem?.children || numberedItems).push(item)
}
if (isTopItems) {
// Add chapter category
numberedItems.push({
type: "category",
title: `Chapter ${padNumber(numbering[0])}`,
children: [],
loaded: true,
})
parentItem = numberedItems[numberedItems.length - 1]
}
// append current number to the item's title
item.number = `${numbering.join(".")}.`
item.title = `${item.number} ${item.title.trim()}`
@@ -17,8 +37,19 @@ export default function numberSidebarItems(sidebarItems, numbering = [1]) {
item.children = numberSidebarItems(item.children, [...numbering, 1])
}
;(parentItem?.children || numberedItems).push(item)
numbering[numbering.length - 1]++
})
return sidebarItems
return numberedItems
}
function padNumber(number) {
number = number.toString()
if (number.length < 2) {
number = `0` + number
}
return number
}
@@ -1,4 +1,4 @@
/** @type {Partial<import("../providers").SidebarItemType>} */
/** @type {Partial<import("@/types").SidebarItem[]>} */
const commonOptions = {
loaded: true,
isPathHref: true,
@@ -6,13 +6,26 @@ const commonOptions = {
/**
*
* @param {import("../providers").SidebarItemType[]} sidebar
* @returns {import("../providers").SidebarItemType[]}
* @param {import("@/types").SidebarItem[]} sidebar
* @param {boolean} nested
* @returns {import("@/types").SidebarItem[]}
*/
export function sidebarAttachHrefCommonOptions(sidebar) {
return sidebar.map((item) => ({
...commonOptions,
...item,
children: sidebarAttachHrefCommonOptions(item.children || []),
}))
export function sidebarAttachHrefCommonOptions(sidebar, nested = false) {
return sidebar.map((item) => {
if (item.type === "separator") {
return item
}
const updatedItem = {
...commonOptions,
...item,
children: sidebarAttachHrefCommonOptions(item.children || [], true),
}
if (updatedItem.type !== "category" && !nested) {
updatedItem.childrenSameLevel = true
}
return updatedItem
})
}
+1 -6
View File
@@ -1,10 +1,8 @@
import type { Metadata } from "next"
import { Inter, Roboto_Mono } from "next/font/google"
import Navbar from "@/components/Navbar"
import Providers from "@/providers"
import "./globals.css"
import { Bannerv2, Breadcrumbs, TightLayout } from "docs-ui"
import { Breadcrumbs, TightLayout } from "docs-ui"
import { config } from "@/config"
import clsx from "clsx"
import { Feedback } from "@/components/Feedback"
@@ -41,14 +39,11 @@ export default function RootLayout({
return (
<TightLayout
ProvidersComponent={Providers}
NavbarComponent={Navbar}
sidebarProps={{
expandItems: true,
banner: <Bannerv2 />,
}}
bodyClassName={clsx(inter.variable, robotoMono.variable)}
>
<Breadcrumbs />
{children}
<Feedback className="my-2" />
<EditButton />
@@ -10,4 +10,4 @@ This section of the documentation provides a reference to the workflows created
You can use these workflows in your customizations as well. They're available in the `@medusajs/core-flows` package.
<ChildDocs childLevel={2} />
<ChildDocs childLevel={2} hideItems={["Overview"]} />
@@ -1,38 +0,0 @@
"use client"
import { Navbar as UiNavbar, getNavbarItems } from "docs-ui"
import { useSidebar } from "docs-ui"
import { basePathUrl } from "../../utils/base-path-url"
import { useMemo } from "react"
import { config } from "../../config"
const Navbar = () => {
const { setMobileSidebarOpen, mobileSidebarOpen } = useSidebar()
const navbarItems = useMemo(
() =>
getNavbarItems({
basePath: config.baseUrl,
activePath: basePathUrl(""),
version: "v2",
}),
[]
)
return (
<UiNavbar
logo={{
light: basePathUrl("/images/logo-icon.png"),
dark: basePathUrl("/images/logo-icon-dark.png"),
}}
items={navbarItems}
mobileMenuButton={{
setMobileSidebarOpen,
mobileSidebarOpen,
}}
isLoading={false}
showSearchOpener
/>
)
}
export default Navbar
+2 -3
View File
@@ -1,4 +1,4 @@
import { DocsConfig } from "types"
import { DocsConfig, SidebarItem } from "types"
import { getMobileSidebarItems } from "docs-ui"
import { generatedSidebar } from "../generated/sidebar.mjs"
@@ -9,8 +9,7 @@ export const config: DocsConfig = {
baseUrl,
basePath: process.env.NEXT_PUBLIC_BASE_PATH,
sidebar: {
top: generatedSidebar,
bottom: [],
default: generatedSidebar as SidebarItem[],
mobile: getMobileSidebarItems({
baseUrl,
version: "v2",
File diff suppressed because it is too large. Load diff
+13 -10
View File
@@ -16,6 +16,7 @@ import {
import SidebarProvider from "./sidebar"
import SearchProvider from "./search"
import { config } from "../config"
import { MainNavProvider } from "./main-nav"
type ProvidersProps = {
children?: React.ReactNode
@@ -35,16 +36,18 @@ const Providers = ({ children }: ProvidersProps) => {
<ScrollControllerProvider scrollableSelector="#main">
<SidebarProvider>
<PaginationProvider>
<SearchProvider>
<HooksLoader
options={{
pageScrollManager: true,
currentLearningPath: true,
}}
>
{children}
</HooksLoader>
</SearchProvider>
<MainNavProvider>
<SearchProvider>
<HooksLoader
options={{
pageScrollManager: true,
currentLearningPath: true,
}}
>
{children}
</HooksLoader>
</SearchProvider>
</MainNavProvider>
</PaginationProvider>
</SidebarProvider>
</ScrollControllerProvider>
+46
View File
@@ -0,0 +1,46 @@
"use client"
import {
formatReportLink,
getNavDropdownItems,
MainNavProvider as UiMainNavProvider,
useIsBrowser,
} from "docs-ui"
import { useMemo } from "react"
import { config } from "../config"
import { basePathUrl } from "../utils/base-path-url"
type MainNavProviderProps = {
children?: React.ReactNode
}
export const MainNavProvider = ({ children }: MainNavProviderProps) => {
const isBrowser = useIsBrowser()
const navigationDropdownItems = useMemo(
() =>
getNavDropdownItems({
basePath: config.baseUrl,
activePath: basePathUrl(),
version: "v2",
}),
[]
)
const reportLink = useMemo(
() =>
formatReportLink(
config.titleSuffix || "",
isBrowser ? document.title : ""
),
[isBrowser]
)
return (
<UiMainNavProvider
navItems={navigationDropdownItems}
reportIssueLink={reportLink}
>
{children}
</UiMainNavProvider>
)
}
-1
View File
@@ -20,7 +20,6 @@ const SidebarProvider = ({ children }: SidebarProviderProps) => {
initialItems={config.sidebar}
staticSidebarItems={true}
disableActiveTransition={true}
noTitleStyling={true}
>
{children}
</UiSidebarProvider>
File diff suppressed because it is too large. Load diff
@@ -1,4 +1,4 @@
/** @type {Partial<import("../types").SidebarItemType>} */
/** @type {Partial<import("../types").RawSidebarItem>} */
const commonOptions = {
loaded: true,
isPathHref: true,
@@ -6,13 +6,19 @@ const commonOptions = {
/**
*
* @param {import("types").SidebarItemType[]} sidebar
* @returns {import("types").SidebarItemType[]}
* @param {import("types").RawSidebarItem[]} sidebar
* @returns {import("types").RawSidebarItem[]}
*/
export function sidebarAttachHrefCommonOptions(sidebar) {
return sidebar.map((item) => ({
...commonOptions,
...item,
children: sidebarAttachHrefCommonOptions(item.children || []),
}))
return sidebar.map((item) => {
if (item.type === "separator") {
return item
}
return {
...commonOptions,
...item,
children: sidebarAttachHrefCommonOptions(item.children || []),
}
})
}
+2 -1
View File
@@ -1,5 +1,6 @@
import { defineDocumentType, makeSource } from "contentlayer/source-files"
import { rehypeComponent } from "./src/lib/rehype-component"
import rehypeSlug from "rehype-slug"
export const Doc = defineDocumentType(() => ({
name: "Doc",
@@ -26,6 +27,6 @@ export default makeSource({
contentDirPath: "./src/content",
documentTypes: [Doc],
mdx: {
rehypePlugins: [rehypeComponent],
rehypePlugins: [[rehypeComponent], [rehypeSlug]],
},
})
+1
View File
@@ -37,6 +37,7 @@
"react": "18.2.0",
"react-day-picker": "^8.10.0",
"react-dom": "18.2.0",
"rehype-slug": "^6.0.0",
"remark": "^14.0.3",
"tailwind": "*",
"tailwindcss": "3.3.3",
+10 -9
View File
@@ -2,7 +2,7 @@ import { MetadataRoute } from "next"
import { docsConfig } from "@/config/docs"
import { absoluteUrl } from "@/lib/absolute-url"
import { SidebarItemType } from "types"
import { SidebarItem } from "types"
export default function sitemap(): MetadataRoute.Sitemap {
const now = new Date()
@@ -12,23 +12,24 @@ export default function sitemap(): MetadataRoute.Sitemap {
lastModified?: string | Date
}> = []
function pushItems(newItems: SidebarItemType[]) {
function pushItems(newItems: SidebarItem[]) {
newItems.forEach((item) => {
if (item.path) {
items.push({
url: absoluteUrl(item.path),
lastModified: now,
})
if (item.type !== "link") {
return
}
items.push({
url: absoluteUrl(item.path),
lastModified: now,
})
if (item.children) {
pushItems(item.children)
}
})
}
pushItems(docsConfig.sidebar.top)
pushItems(docsConfig.sidebar.bottom)
pushItems(docsConfig.sidebar.default)
return items
}
+1 -2
View File
@@ -1,6 +1,5 @@
import type { Metadata } from "next"
import { Navbar } from "@/components/navbar"
import { Providers } from "@/providers"
import { siteConfig } from "@/config/site"
@@ -36,11 +35,11 @@ export default function RootLayout({
return (
<TightLayout
ProvidersComponent={Providers}
NavbarComponent={Navbar}
sidebarProps={{
expandItems: true,
}}
bodyClassName={clsx(inter.variable, robotoMono.variable)}
showBanner={false}
>
{children}
</TightLayout>
-25
View File
@@ -1,25 +0,0 @@
"use client"
import { docsConfig } from "@/config/docs"
import { basePathUrl } from "@/lib/base-path-url"
import { Navbar as UiNavbar, useSidebar } from "docs-ui"
const Navbar = () => {
const { mobileSidebarOpen, setMobileSidebarOpen } = useSidebar()
return (
<UiNavbar
logo={{
light: basePathUrl("/images/logo-icon.png"),
dark: basePathUrl("/images/logo-icon-dark.png"),
}}
items={docsConfig.mainNav}
mobileMenuButton={{
setMobileSidebarOpen,
mobileSidebarOpen,
}}
/>
)
}
export { Navbar }
+113 -34
View File
@@ -1,281 +1,360 @@
import { ArrowUpRightOnBox } from "@medusajs/icons"
import { NavbarItem, getMobileSidebarItems, getNavbarItems } from "docs-ui"
import { SidebarSectionItemsType } from "types"
import { getMobileSidebarItems } from "docs-ui"
import { SidebarSectionItems } from "types"
import { siteConfig } from "./site"
type DocsConfig = {
mainNav: NavbarItem[]
sidebar: SidebarSectionItemsType
sidebar: SidebarSectionItems
}
export const docsConfig: DocsConfig = {
mainNav: getNavbarItems({
basePath: siteConfig.baseUrl,
activePath: process.env.NEXT_PUBLIC_BASE_PATH || "/ui",
version: "v1",
}),
sidebar: {
top: [
default: [
{
title: "Getting Started",
children: [
{
title: "Introduction",
path: "/",
loaded: true,
isPathHref: true,
},
],
type: "link",
title: "Introduction",
path: "/",
loaded: true,
isPathHref: true,
},
{
type: "separator",
},
{
type: "category",
title: "Installation",
loaded: true,
children: [
{
type: "link",
title: "Medusa Admin Extension",
path: "/installation/medusa-admin-extension",
isPathHref: true,
loaded: true,
},
{
type: "link",
title: "Standalone Project",
path: "/installation/standalone-project",
isPathHref: true,
loaded: true,
},
{
type: "link",
title: "Upgrade Guides",
path: `${process.env.NEXT_PUBLIC_DOCS_URL}/upgrade-guides/medusa-ui`,
isPathHref: true,
additionalElms: <ArrowUpRightOnBox />,
linkProps: {
target: "_blank",
rel: "noreferrer",
},
loaded: true,
},
],
},
],
bottom: [
{
type: "category",
title: "Colors",
loaded: true,
children: [
{
type: "link",
title: "Overview",
path: "/colors/overview",
isPathHref: true,
loaded: true,
},
],
},
{
type: "link",
title: "Icons",
children: [
{
title: "Overview",
path: "/icons/overview",
isPathHref: true,
},
],
path: "/icons/overview",
isPathHref: true,
loaded: true,
},
{
type: "separator",
},
{
type: "category",
title: "Components",
loaded: true,
children: [
{
type: "link",
title: "Alert",
path: "/components/alert",
isPathHref: true,
loaded: true,
},
{
type: "link",
title: "Avatar",
path: "/components/avatar",
isPathHref: true,
loaded: true,
},
{
type: "link",
title: "Badge",
path: "/components/badge",
isPathHref: true,
loaded: true,
},
{
type: "link",
title: "Button",
path: "/components/button",
isPathHref: true,
loaded: true,
},
{
type: "link",
title: "Calendar",
path: "/components/calendar",
isPathHref: true,
loaded: true,
},
{
type: "link",
title: "Checkbox",
path: "/components/checkbox",
isPathHref: true,
loaded: true,
},
{
type: "link",
title: "Code Block",
path: "/components/code-block",
isPathHref: true,
loaded: true,
},
{
type: "link",
title: "Command",
path: "/components/command",
isPathHref: true,
loaded: true,
},
{
type: "link",
title: "Command Bar",
path: "/components/command-bar",
isPathHref: true,
loaded: true,
},
{
type: "link",
title: "Container",
path: "/components/container",
isPathHref: true,
loaded: true,
},
{
type: "link",
title: "Copy",
path: "/components/copy",
isPathHref: true,
loaded: true,
},
{
type: "link",
title: "Currency Input",
path: "/components/currency-input",
isPathHref: true,
loaded: true,
},
{
type: "link",
title: "Date Picker",
path: "/components/date-picker",
isPathHref: true,
loaded: true,
},
{
type: "link",
title: "Drawer",
path: "/components/drawer",
isPathHref: true,
loaded: true,
},
{
type: "link",
title: "Dropdown Menu",
path: "/components/dropdown-menu",
isPathHref: true,
loaded: true,
},
{
type: "link",
title: "Focus Modal",
path: "/components/focus-modal",
isPathHref: true,
loaded: true,
},
{
type: "link",
title: "Heading",
path: "/components/heading",
isPathHref: true,
loaded: true,
},
{
type: "link",
title: "Icon Badge",
path: "/components/icon-badge",
isPathHref: true,
loaded: true,
},
{
type: "link",
title: "Icon Button",
path: "/components/icon-button",
isPathHref: true,
loaded: true,
},
{
type: "link",
title: "Input",
path: "/components/input",
isPathHref: true,
loaded: true,
},
{
type: "link",
title: "Kbd",
path: "/components/kbd",
isPathHref: true,
loaded: true,
},
{
type: "link",
title: "Label",
path: "/components/label",
isPathHref: true,
loaded: true,
},
{
type: "link",
title: "Progress Accordion",
path: "/components/progress-accordion",
isPathHref: true,
loaded: true,
},
{
type: "link",
title: "Progress Tabs",
path: "/components/progress-tabs",
isPathHref: true,
loaded: true,
},
{
type: "link",
title: "Prompt",
path: "/components/prompt",
isPathHref: true,
loaded: true,
},
{
type: "link",
title: "Radio Group",
path: "/components/radio-group",
isPathHref: true,
loaded: true,
},
{
type: "link",
title: "Select",
path: "/components/select",
isPathHref: true,
loaded: true,
},
{
type: "link",
title: "Status Badge",
path: "/components/status-badge",
isPathHref: true,
loaded: true,
},
{
type: "link",
title: "Switch",
path: "/components/switch",
isPathHref: true,
loaded: true,
},
{
type: "link",
title: "Table",
path: "/components/table",
isPathHref: true,
loaded: true,
},
{
type: "link",
title: "Tabs",
path: "/components/tabs",
isPathHref: true,
loaded: true,
},
{
type: "link",
title: "Text",
path: "/components/text",
isPathHref: true,
loaded: true,
},
{
type: "link",
title: "Textarea",
path: "/components/textarea",
isPathHref: true,
loaded: true,
},
{
type: "link",
title: "Toast",
path: "/components/toast",
isPathHref: true,
loaded: true,
},
{
type: "link",
title: "Tooltip",
path: "/components/tooltip",
isPathHref: true,
loaded: true,
},
],
},
{
type: "category",
title: "Hooks",
loaded: true,
children: [
{
type: "link",
title: "usePrompt",
path: "/hooks/use-prompt",
isPathHref: true,
loaded: true,
},
{
type: "link",
title: "useToggleState",
path: "/hooks/use-toggle-state",
isPathHref: true,
loaded: true,
},
],
},
{
type: "category",
title: "Utils",
loaded: true,
children: [
{
type: "link",
title: "clx",
path: "/utils/clx",
isPathHref: true,
loaded: true,
},
],
},
+1 -2
View File
@@ -16,8 +16,7 @@ export const siteConfig: SiteConfig = {
description: "Primitives for building Medusa applications.",
// sidebar is defined in docs.tsx
sidebar: {
top: [],
bottom: [],
default: [],
mobile: [],
},
}
+4 -1
View File
@@ -11,6 +11,7 @@ import {
import SearchProvider from "./search"
import SidebarProvider from "./sidebar"
import { siteConfig } from "../config/site"
import { MainNavProvider } from "./main-nav"
type ProvidersProps = {
children: React.ReactNode
@@ -25,7 +26,9 @@ const Providers = ({ children }: ProvidersProps) => {
<ModalProvider>
<ScrollControllerProvider scrollableSelector="#main">
<SidebarProvider>
<SearchProvider>{children}</SearchProvider>
<MainNavProvider>
<SearchProvider>{children}</SearchProvider>
</MainNavProvider>
</SidebarProvider>
</ScrollControllerProvider>
</ModalProvider>
+42
View File
@@ -0,0 +1,42 @@
"use client"
import {
formatReportLink,
getNavDropdownItems,
MainNavProvider as UiMainNavProvider,
useIsBrowser,
} from "docs-ui"
import { useMemo } from "react"
import { siteConfig } from "../config/site"
import { basePathUrl } from "../lib/base-path-url"
type MainNavProviderProps = {
children?: React.ReactNode
}
export const MainNavProvider = ({ children }: MainNavProviderProps) => {
const isBrowser = useIsBrowser()
const navigationDropdownItems = useMemo(
() =>
getNavDropdownItems({
basePath: siteConfig.baseUrl,
activePath: basePathUrl(),
version: "v1",
}),
[]
)
const reportLink = useMemo(
() => formatReportLink("UI Docs", isBrowser ? document.title : "", "ui"),
[isBrowser]
)
return (
<UiMainNavProvider
navItems={navigationDropdownItems}
reportIssueLink={reportLink}
>
{children}
</UiMainNavProvider>
)
}
+1
View File
@@ -10,6 +10,7 @@ type SidebarProviderProps = {
const SidebarProvider = ({ children }: SidebarProviderProps) => {
const { scrollableElement } = useScrollController()
return (
<UiSidebarProvider
initialItems={docsConfig.sidebar}
-3
View File
@@ -1,7 +1,5 @@
import type { Metadata } from "next"
import { Inter, Roboto_Mono } from "next/font/google"
import Navbar from "@/components/Navbar"
import Providers from "@/providers"
import "../css/globals.css"
import { TightLayout } from "docs-ui"
@@ -40,7 +38,6 @@ export default function RootLayout({
return (
<TightLayout
ProvidersComponent={Providers}
NavbarComponent={Navbar}
sidebarProps={{
expandItems: true,
}}
@@ -1,38 +0,0 @@
"use client"
import { Navbar as UiNavbar, getNavbarItems } from "docs-ui"
import { useSidebar } from "docs-ui"
import { basePathUrl } from "../../utils/base-path-url"
import { useMemo } from "react"
import { config } from "../../config"
const Navbar = () => {
const { setMobileSidebarOpen, mobileSidebarOpen } = useSidebar()
const navbarItems = useMemo(
() =>
getNavbarItems({
basePath: config.baseUrl,
activePath: process.env.NEXT_PUBLIC_BASE_PATH || "/user-guide",
version: "v2",
}),
[]
)
return (
<UiNavbar
logo={{
light: basePathUrl("/images/logo-icon.png"),
dark: basePathUrl("/images/logo-icon-dark.png"),
}}
items={navbarItems}
mobileMenuButton={{
setMobileSidebarOpen,
mobileSidebarOpen,
}}
isLoading={false}
/>
)
}
export default Navbar
+2 -3
View File
@@ -1,4 +1,4 @@
import { DocsConfig } from "types"
import { DocsConfig, SidebarItem } from "types"
import { getMobileSidebarItems } from "docs-ui"
import { generatedSidebar as sidebar } from "@/generated/sidebar.mjs"
@@ -9,8 +9,7 @@ export const config: DocsConfig = {
baseUrl,
basePath: process.env.NEXT_PUBLIC_BASE_PATH,
sidebar: {
top: sidebar,
bottom: [],
default: sidebar as SidebarItem[],
mobile: getMobileSidebarItems({
baseUrl,
version: "v2",
+61
View File
@@ -2,13 +2,18 @@ export const generatedSidebar = [
{
"loaded": true,
"isPathHref": true,
"type": "link",
"path": "/",
"title": "Introduction",
"children": []
},
{
"type": "separator"
},
{
"loaded": true,
"isPathHref": true,
"type": "category",
"title": "Tips",
"hasTitleStyling": true,
"autogenerate_path": "/tips",
@@ -16,6 +21,7 @@ export const generatedSidebar = [
{
"loaded": true,
"isPathHref": true,
"type": "link",
"path": "/tips/bulk-editor",
"title": "Bulk Editor",
"children": []
@@ -23,6 +29,7 @@ export const generatedSidebar = [
{
"loaded": true,
"isPathHref": true,
"type": "link",
"path": "/tips/languages",
"title": "Admin Languages",
"children": []
@@ -30,6 +37,7 @@ export const generatedSidebar = [
{
"loaded": true,
"isPathHref": true,
"type": "link",
"path": "/tips/lists",
"title": "Lists",
"children": []
@@ -39,6 +47,7 @@ export const generatedSidebar = [
{
"loaded": true,
"isPathHref": true,
"type": "category",
"path": "/orders",
"title": "Orders",
"hasTitleStyling": true,
@@ -47,6 +56,7 @@ export const generatedSidebar = [
{
"loaded": true,
"isPathHref": true,
"type": "link",
"path": "/orders/manage",
"title": "Manage Details",
"children": []
@@ -54,6 +64,7 @@ export const generatedSidebar = [
{
"loaded": true,
"isPathHref": true,
"type": "link",
"path": "/orders/payments",
"title": "Manage Payments",
"children": []
@@ -61,6 +72,7 @@ export const generatedSidebar = [
{
"loaded": true,
"isPathHref": true,
"type": "link",
"path": "/orders/fulfillments",
"title": "Manage Fulfillments",
"children": []
@@ -68,6 +80,7 @@ export const generatedSidebar = [
{
"loaded": true,
"isPathHref": true,
"type": "link",
"path": "/orders/edit",
"title": "Edit an Order’s Items",
"children": []
@@ -75,6 +88,7 @@ export const generatedSidebar = [
{
"loaded": true,
"isPathHref": true,
"type": "link",
"path": "/orders/drafts",
"title": "Manage Draft Orders",
"children": []
@@ -82,6 +96,7 @@ export const generatedSidebar = [
{
"loaded": true,
"isPathHref": true,
"type": "link",
"path": "/orders/returns",
"title": "Manage Returns",
"children": []
@@ -89,6 +104,7 @@ export const generatedSidebar = [
{
"loaded": true,
"isPathHref": true,
"type": "link",
"path": "/orders/exchange",
"title": "Manage Exchanges",
"children": []
@@ -96,6 +112,7 @@ export const generatedSidebar = [
{
"loaded": true,
"isPathHref": true,
"type": "link",
"path": "/orders/claims",
"title": "Manage Order's Claims",
"children": []
@@ -103,6 +120,7 @@ export const generatedSidebar = [
{
"loaded": true,
"isPathHref": true,
"type": "link",
"path": "/orders/export",
"title": "Export Orders",
"children": []
@@ -112,6 +130,7 @@ export const generatedSidebar = [
{
"loaded": true,
"isPathHref": true,
"type": "category",
"path": "/products",
"title": "Products",
"hasTitleStyling": true,
@@ -120,6 +139,7 @@ export const generatedSidebar = [
{
"loaded": true,
"isPathHref": true,
"type": "link",
"path": "/products/manage",
"title": "Manage Products",
"children": []
@@ -127,6 +147,7 @@ export const generatedSidebar = [
{
"loaded": true,
"isPathHref": true,
"type": "link",
"path": "/products/collections",
"title": "Manage Product Collections",
"children": []
@@ -134,6 +155,7 @@ export const generatedSidebar = [
{
"loaded": true,
"isPathHref": true,
"type": "link",
"path": "/products/categories",
"title": "Manage Product Categories",
"children": []
@@ -141,12 +163,14 @@ export const generatedSidebar = [
{
"loaded": true,
"isPathHref": true,
"type": "link",
"path": "/products/gift-cards",
"title": "Gift Cards",
"children": [
{
"loaded": true,
"isPathHref": true,
"type": "link",
"path": "/products/gift-cards/product-gift-card",
"title": "Manage a Product Gift Card",
"children": [],
@@ -155,6 +179,7 @@ export const generatedSidebar = [
{
"loaded": true,
"isPathHref": true,
"type": "link",
"path": "/products/gift-cards/customer-gift-card",
"title": "Manage a Customer Gift Card",
"children": [],
@@ -165,6 +190,7 @@ export const generatedSidebar = [
{
"loaded": true,
"isPathHref": true,
"type": "link",
"path": "/products/import",
"title": "Import Products",
"children": []
@@ -172,6 +198,7 @@ export const generatedSidebar = [
{
"loaded": true,
"isPathHref": true,
"type": "link",
"path": "/products/export",
"title": "Export Products",
"children": []
@@ -181,6 +208,7 @@ export const generatedSidebar = [
{
"loaded": true,
"isPathHref": true,
"type": "category",
"path": "/inventory",
"title": "Inventory",
"hasTitleStyling": true,
@@ -189,6 +217,7 @@ export const generatedSidebar = [
{
"loaded": true,
"isPathHref": true,
"type": "link",
"path": "/inventory/inventory",
"title": "Manage Inventory",
"children": []
@@ -196,6 +225,7 @@ export const generatedSidebar = [
{
"loaded": true,
"isPathHref": true,
"type": "link",
"path": "/inventory/reservations",
"title": "Manage Reservations",
"children": []
@@ -205,6 +235,7 @@ export const generatedSidebar = [
{
"loaded": true,
"isPathHref": true,
"type": "category",
"path": "/customers",
"title": "Customers",
"hasTitleStyling": true,
@@ -213,6 +244,7 @@ export const generatedSidebar = [
{
"loaded": true,
"isPathHref": true,
"type": "link",
"path": "/customers/manage",
"title": "Manage Customers",
"children": []
@@ -220,6 +252,7 @@ export const generatedSidebar = [
{
"loaded": true,
"isPathHref": true,
"type": "link",
"path": "/customers/groups",
"title": "Manage Customer Groups",
"children": []
@@ -229,6 +262,7 @@ export const generatedSidebar = [
{
"loaded": true,
"isPathHref": true,
"type": "category",
"path": "/discounts",
"title": "Discounts",
"hasTitleStyling": true,
@@ -237,6 +271,7 @@ export const generatedSidebar = [
{
"loaded": true,
"isPathHref": true,
"type": "link",
"path": "/discounts/create",
"title": "Create a Discount",
"children": []
@@ -244,6 +279,7 @@ export const generatedSidebar = [
{
"loaded": true,
"isPathHref": true,
"type": "link",
"path": "/discounts/manage",
"title": "Manage Discounts",
"children": []
@@ -253,6 +289,7 @@ export const generatedSidebar = [
{
"loaded": true,
"isPathHref": true,
"type": "category",
"path": "/pricing",
"title": "Pricing",
"hasTitleStyling": true,
@@ -261,6 +298,7 @@ export const generatedSidebar = [
{
"loaded": true,
"isPathHref": true,
"type": "link",
"path": "/pricing/create",
"title": "Create a Price List",
"children": []
@@ -268,6 +306,7 @@ export const generatedSidebar = [
{
"loaded": true,
"isPathHref": true,
"type": "link",
"path": "/pricing/manage",
"title": "Manage Price Lists",
"children": []
@@ -277,6 +316,7 @@ export const generatedSidebar = [
{
"loaded": true,
"isPathHref": true,
"type": "category",
"path": "/settings",
"title": "Settings",
"hasTitleStyling": true,
@@ -285,6 +325,7 @@ export const generatedSidebar = [
{
"loaded": true,
"isPathHref": true,
"type": "link",
"path": "/settings/profile",
"title": "Profile",
"children": []
@@ -292,6 +333,7 @@ export const generatedSidebar = [
{
"loaded": true,
"isPathHref": true,
"type": "link",
"path": "/settings/store",
"title": "Store",
"children": []
@@ -299,12 +341,14 @@ export const generatedSidebar = [
{
"loaded": true,
"isPathHref": true,
"type": "link",
"path": "/settings/users",
"title": "Users",
"children": [
{
"loaded": true,
"isPathHref": true,
"type": "link",
"path": "/settings/users/invites",
"title": "Manage Invites",
"children": [],
@@ -315,12 +359,14 @@ export const generatedSidebar = [
{
"loaded": true,
"isPathHref": true,
"type": "link",
"path": "/settings/regions",
"title": "Regions",
"children": [
{
"loaded": true,
"isPathHref": true,
"type": "link",
"path": "/settings/regions/manage",
"title": "Manage Regions",
"children": [],
@@ -329,6 +375,7 @@ export const generatedSidebar = [
{
"loaded": true,
"isPathHref": true,
"type": "link",
"path": "/settings/regions/countries",
"title": "Manage Countries",
"children": [],
@@ -337,6 +384,7 @@ export const generatedSidebar = [
{
"loaded": true,
"isPathHref": true,
"type": "link",
"path": "/settings/regions/providers",
"title": "Manage Providers",
"children": [],
@@ -345,6 +393,7 @@ export const generatedSidebar = [
{
"loaded": true,
"isPathHref": true,
"type": "link",
"path": "/settings/regions/shipping-options",
"title": "Manage Shipping Options",
"children": [],
@@ -355,6 +404,7 @@ export const generatedSidebar = [
{
"loaded": true,
"isPathHref": true,
"type": "link",
"path": "/settings/return-reasons",
"title": "Return Reasons",
"children": []
@@ -362,12 +412,14 @@ export const generatedSidebar = [
{
"loaded": true,
"isPathHref": true,
"type": "link",
"path": "/settings/taxes",
"title": "Taxes",
"children": [
{
"loaded": true,
"isPathHref": true,
"type": "link",
"path": "/settings/taxes/manage",
"title": "Manage Taxes",
"children": [],
@@ -376,6 +428,7 @@ export const generatedSidebar = [
{
"loaded": true,
"isPathHref": true,
"type": "link",
"path": "/settings/taxes/tax-rates",
"title": "Manage Tax Rates",
"children": [],
@@ -386,6 +439,7 @@ export const generatedSidebar = [
{
"loaded": true,
"isPathHref": true,
"type": "link",
"path": "/settings/locations",
"title": "Locations",
"children": []
@@ -393,12 +447,14 @@ export const generatedSidebar = [
{
"loaded": true,
"isPathHref": true,
"type": "link",
"path": "/settings/sales-channels",
"title": "Sales Channels",
"children": [
{
"loaded": true,
"isPathHref": true,
"type": "link",
"path": "/settings/sales-channels/manage",
"title": "Manage Sales Channels",
"children": [],
@@ -407,6 +463,7 @@ export const generatedSidebar = [
{
"loaded": true,
"isPathHref": true,
"type": "link",
"path": "/settings/sales-channels/products",
"title": "Manage Products",
"children": [],
@@ -417,18 +474,21 @@ export const generatedSidebar = [
{
"loaded": true,
"isPathHref": true,
"type": "link",
"path": "/settings/developer",
"title": "Developer",
"children": [
{
"loaded": true,
"isPathHref": true,
"type": "link",
"path": "/settings/developer/api-key-management",
"title": "API Key Management",
"children": [
{
"loaded": true,
"isPathHref": true,
"type": "link",
"path": "/settings/developer/api-key-management/sales-channels",
"title": "Manage Sales Channels",
"children": [],
@@ -440,6 +500,7 @@ export const generatedSidebar = [
{
"loaded": true,
"isPathHref": true,
"type": "link",
"path": "/settings/developer/executions",
"title": "Executions",
"children": [],
+12 -9
View File
@@ -15,6 +15,7 @@ import {
import SidebarProvider from "./sidebar"
import SearchProvider from "./search"
import { config } from "../config"
import { MainNavProvider } from "./main-nav"
type ProvidersProps = {
children?: React.ReactNode
@@ -32,15 +33,17 @@ const Providers = ({ children }: ProvidersProps) => {
<ScrollControllerProvider scrollableSelector="#main">
<SidebarProvider>
<PaginationProvider>
<SearchProvider>
<HooksLoader
options={{
pageScrollManager: true,
}}
>
{children}
</HooksLoader>
</SearchProvider>
<MainNavProvider>
<SearchProvider>
<HooksLoader
options={{
pageScrollManager: true,
}}
>
{children}
</HooksLoader>
</SearchProvider>
</MainNavProvider>
</PaginationProvider>
</SidebarProvider>
</ScrollControllerProvider>
@@ -0,0 +1,46 @@
"use client"
import {
formatReportLink,
getNavDropdownItems,
MainNavProvider as UiMainNavProvider,
useIsBrowser,
} from "docs-ui"
import { useMemo } from "react"
import { config } from "../config"
import { basePathUrl } from "../utils/base-path-url"
type MainNavProviderProps = {
children?: React.ReactNode
}
export const MainNavProvider = ({ children }: MainNavProviderProps) => {
const isBrowser = useIsBrowser()
const navigationDropdownItems = useMemo(
() =>
getNavDropdownItems({
basePath: config.baseUrl,
activePath: basePathUrl(),
version: "v2",
}),
[]
)
const reportLink = useMemo(
() =>
formatReportLink(
config.titleSuffix || "",
isBrowser ? document.title : ""
),
[isBrowser]
)
return (
<UiMainNavProvider
navItems={navigationDropdownItems}
reportIssueLink={reportLink}
>
{children}
</UiMainNavProvider>
)
}
@@ -20,7 +20,6 @@ const SidebarProvider = ({ children }: SidebarProviderProps) => {
initialItems={config.sidebar}
staticSidebarItems={true}
disableActiveTransition={true}
noTitleStyling={true}
>
{children}
</UiSidebarProvider>
+12
View File
@@ -5,51 +5,63 @@ import { sidebarAttachHrefCommonOptions } from "build-scripts"
/** @type {import('types').RawSidebarItemType[]} */
export const sidebar = sidebarAttachHrefCommonOptions([
{
type: "link",
path: "/",
title: "Introduction",
},
{
type: "separator",
},
{
type: "category",
title: "Tips",
hasTitleStyling: true,
autogenerate_path: "/tips",
},
{
type: "category",
path: "/orders",
title: "Orders",
hasTitleStyling: true,
autogenerate_path: "/orders",
},
{
type: "category",
path: "/products",
title: "Products",
hasTitleStyling: true,
autogenerate_path: "/products",
},
{
type: "category",
path: "/inventory",
title: "Inventory",
hasTitleStyling: true,
autogenerate_path: "/inventory",
},
{
type: "category",
path: "/customers",
title: "Customers",
hasTitleStyling: true,
autogenerate_path: "/customers",
},
{
type: "category",
path: "/discounts",
title: "Discounts",
hasTitleStyling: true,
autogenerate_path: "/discounts",
},
{
type: "category",
path: "/pricing",
title: "Pricing",
hasTitleStyling: true,
autogenerate_path: "/pricing",
},
{
type: "category",
path: "/settings",
title: "Settings",
hasTitleStyling: true,