add how-to sidebar

This commit is contained in:
Shahed Nasser
2025-03-10 13:38:55 +02:00
parent 8b1ee3705e
commit e2d832ebc2
11 changed files with 310 additions and 120 deletions

View File

@@ -1,20 +1,24 @@
import { ChildDocs } from "docs-ui"
export const metadata = {
title: `Admin Components`,
title: `Admin Components & Layouts`,
}
# {metadata.title}
In this section, you'll find examples of implementing common Medusa Admin components and layouts.
In this section of the documentation, you'll learn how to implement common Medusa Admin components and layouts.
These components are useful to follow the same design conventions as the Medusa Admin, and are build on top of the [Medusa UI package](!ui!).
These guides are useful to build components and layouts that follow the same design conventions as the Medusa Admin. The components and layouts are built on top of the [Medusa UI package](!ui!).
<Note title="Tip">
Refer to the [Medusa UI documentation](!ui!) for a full list of components.
</Note>
## Layouts
Use these components to set the layout of your UI route.
These layout components allow you to set the layout of your [UI routes](!docs!/learn/fundamentals/admin/ui-routes) similar to the layouts used in the Medusa Admin.
<ChildDocs showItems={["Layouts"]} onlyTopLevel={false} hideTitle />
@@ -22,6 +26,6 @@ Use these components to set the layout of your UI route.
## Components
Use these components in your widgets and UI routes.
These components allow you to use common Medusa Admin components in your custom UI routes and widgets.
<ChildDocs showItems={["Components"]} onlyTopLevel={false} hideTitle />

View File

@@ -1,4 +1,4 @@
import { ChildDocs } from "docs-ui"
import { CardList, Card } from "docs-ui"
export const metadata = {
title: `Deployments`,
@@ -32,7 +32,20 @@ With Medusa Cloud, you maintain full customization control as you deploy your ow
To host and maintain Medusa on your own, check out the following guides.
<ChildDocs showItems={["Self-Hosting"]} hideTitle={true} />
<CardList
items={[
{
title: "General Guide",
href: "https://docs.medusajs.com/learn/deployment/general",
text: "General steps to deploy Medusa.",
},
{
title: "Railway",
href: "/deployment/medusa-application/railway",
text: "Deploy Medusa on Railway.",
}
]}
/>
---
@@ -40,4 +53,8 @@ To host and maintain Medusa on your own, check out the following guides.
Learn how to deploy the Next.js Starter Storefront.
<ChildDocs showItems={["Next.js Starter"]} hideTitle={true} />
<Card
title="Vercel"
path="/deployment/storefront/vercel"
text="Deploy the Next.js Starter Storefront on Vercel."
/>

View File

@@ -0,0 +1,25 @@
import { ChildDocs } from "docs-ui"
export const metadata = {
title: `How-to & Tutorials`,
}
# {metadata.title}
In this section of the documentation, you'll find how-to guides and tutorials that will help you customize the Medusa server and admin. These guides are useful after you've learned Medusa's main concepts in the [Get Started](!docs!/learn) section of the documentation.
You can follow these guides to learn how to customize the Medusa server and admin to fit your business requirements. This section of the documentation also includes deployment guides to help you deploy your Medusa server and admin to different platforms.
## Example Snippets
For a quick access to code snippets of the different concepts you learned about, such as API routes and workflows, refer to the [Examples Snippets](../examples/page.mdx) documentation.
---
<ChildDocs showItems={["How-To Guides", "Tutorials"]} defaultItemsPerRow={2} />
---
## Deployment Guides
Deployment guides are a collection of guides that help you deploy your Medusa server and admin to different platforms. Learn more in the [Deployment Overview](../deployment/page.mdx) documentation.

View File

@@ -20,7 +20,7 @@ Through this reference, you'll learn about the available workflows and steps in
All workflows and steps in this reference are exported by the `@medusajs/medusa/core-flows` package.
<ChildDocs childLevel={2} hideItems={["Overview", "Steps"]} defaultItemsPerRow={2} search={{
<ChildDocs startChildLevel={2} hideItems={["Overview", "Steps"]} defaultItemsPerRow={2} search={{
enable: true,
placeholder: "Search workflows...",
storageKey: "medusa-workflows-reference",

View File

@@ -2101,7 +2101,7 @@ export const generatedEditDates = {
"app/admin-components/components/json-view-section/page.mdx": "2024-10-07T11:15:58.833Z",
"app/admin-components/components/section-row/page.mdx": "2024-10-07T11:15:58.832Z",
"app/admin-components/components/table/page.mdx": "2025-03-03T14:53:37.952Z",
"app/admin-components/page.mdx": "2025-03-07T08:00:46.960Z",
"app/admin-components/page.mdx": "2025-03-10T10:42:41.345Z",
"app/admin-components/layouts/single-column/page.mdx": "2024-10-07T11:16:06.435Z",
"app/admin-components/layouts/two-column/page.mdx": "2024-10-07T11:16:10.092Z",
"app/admin-components/components/forms/page.mdx": "2024-10-09T12:48:04.229Z",
@@ -6039,5 +6039,6 @@ export const generatedEditDates = {
"references/core_flows/types/core_flows.RefreshCartItemsWorkflowInput/page.mdx": "2025-03-04T13:33:46.131Z",
"references/core_flows/types/core_flows.RefreshCartShippingMethodsWorkflowInput/page.mdx": "2025-03-04T13:33:46.133Z",
"references/core_flows/types/core_flows.ValidateExistingPaymentCollectionStepInput/page.mdx": "2025-03-04T13:33:46.130Z",
"references/types/interfaces/types.ITaxProvider/page.mdx": "2025-03-04T13:33:52.645Z"
"references/types/interfaces/types.ITaxProvider/page.mdx": "2025-03-04T13:33:52.645Z",
"app/how-to-tutorials/page.mdx": "2025-03-10T09:33:49.208Z"
}

View File

@@ -787,14 +787,14 @@ export const filesMap = [
"filePath": "/www/apps/resources/app/examples/guides/custom-item-price/page.mdx",
"pathname": "/examples/guides/custom-item-price"
},
{
"filePath": "/www/apps/resources/app/examples/guides/quote-management/page.mdx",
"pathname": "/examples/guides/quote-management"
},
{
"filePath": "/www/apps/resources/app/examples/page.mdx",
"pathname": "/examples"
},
{
"filePath": "/www/apps/resources/app/how-to-tutorials/page.mdx",
"pathname": "/how-to-tutorials"
},
{
"filePath": "/www/apps/resources/app/integrations/guides/resend/page.mdx",
"pathname": "/integrations/guides/resend"

View File

@@ -26,6 +26,7 @@ const generatedgeneratedHowToTutorialsSidebarSidebar = {
"isPathHref": true,
"type": "category",
"title": "How-To Guides",
"description": "How-to guides are a collection of guides that help you understand how to achieve certain customizations or implementing specific features in Medusa.",
"children": [
{
"loaded": true,
@@ -35,6 +36,7 @@ const generatedgeneratedHowToTutorialsSidebarSidebar = {
"autogenerate_tags": "howTo+server",
"autogenerate_as_ref": true,
"sort_sidebar": "alphabetize",
"description": "These how-to guides help you customize the Medusa server to implement custom features and business logic.",
"children": [
{
"loaded": true,
@@ -146,29 +148,130 @@ const generatedgeneratedHowToTutorialsSidebarSidebar = {
{
"loaded": true,
"isPathHref": true,
"type": "link",
"path": "/admin-components",
"title": "Overview",
"children": []
},
{
"type": "separator"
},
{
"loaded": true,
"isPathHref": true,
"type": "category",
"title": "Components",
"autogenerate_path": "/admin-components/components",
"children": []
},
{
"loaded": true,
"isPathHref": true,
"type": "category",
"title": "Layouts",
"autogenerate_path": "/admin-components/layouts",
"children": []
"type": "sidebar",
"sidebar_id": "admin-components-layouts",
"title": "Components & Layouts",
"children": [
{
"loaded": true,
"isPathHref": true,
"type": "link",
"path": "/admin-components",
"title": "Overview",
"children": []
},
{
"type": "separator"
},
{
"loaded": true,
"isPathHref": true,
"type": "category",
"title": "Layouts",
"autogenerate_path": "/admin-components/layouts",
"children": [
{
"loaded": true,
"isPathHref": true,
"type": "link",
"path": "/admin-components/layouts/single-column",
"title": "Single Column",
"description": "",
"children": []
},
{
"loaded": true,
"isPathHref": true,
"type": "link",
"path": "/admin-components/layouts/two-column",
"title": "Two Column",
"description": "",
"children": []
}
]
},
{
"loaded": true,
"isPathHref": true,
"type": "category",
"title": "Components",
"autogenerate_path": "/admin-components/components",
"children": [
{
"loaded": true,
"isPathHref": true,
"type": "link",
"path": "/admin-components/components/action-menu",
"title": "Action Menu",
"description": "",
"children": []
},
{
"loaded": true,
"isPathHref": true,
"type": "link",
"path": "/admin-components/components/container",
"title": "Container",
"description": "",
"children": []
},
{
"loaded": true,
"isPathHref": true,
"type": "link",
"path": "/admin-components/components/data-table",
"title": "Data Table",
"description": "",
"children": []
},
{
"loaded": true,
"isPathHref": true,
"type": "link",
"path": "/admin-components/components/forms",
"title": "Forms",
"description": "",
"children": []
},
{
"loaded": true,
"isPathHref": true,
"type": "link",
"path": "/admin-components/components/header",
"title": "Header",
"description": "",
"children": []
},
{
"loaded": true,
"isPathHref": true,
"type": "link",
"path": "/admin-components/components/json-view-section",
"title": "JSON View",
"description": "",
"children": []
},
{
"loaded": true,
"isPathHref": true,
"type": "link",
"path": "/admin-components/components/section-row",
"title": "Section Row",
"description": "",
"children": []
},
{
"loaded": true,
"isPathHref": true,
"type": "link",
"path": "/admin-components/components/table",
"title": "Table",
"description": "",
"children": []
}
]
}
]
}
]
}
@@ -179,6 +282,7 @@ const generatedgeneratedHowToTutorialsSidebarSidebar = {
"isPathHref": true,
"type": "category",
"title": "Tutorials",
"description": "Tutorials are step-by-step guides that take you through implementing a specific use case in Medusa. You can follow these guides whether you're a beginner or an experienced Medusa developer.\n\nWhile tutorials show you a specific use case, they also help you understand how to implement similar use cases in your own projects. Also, you can implement the use case in a tutorial differently to fit your business requirements.",
"children": [
{
"loaded": true,
@@ -186,15 +290,16 @@ const generatedgeneratedHowToTutorialsSidebarSidebar = {
"type": "link",
"title": "Custom Item Pricing",
"path": "/examples/guides/custom-item-price",
"description": "Learn how to use prices from external systems for products.",
"children": []
},
{
"loaded": true,
"isPathHref": true,
"type": "link",
"title": "Wishlist",
"title": "Wishlist Plugin",
"path": "/plugins/guides/wishlist",
"description": "Learn how to build a wishlist plugin.",
"description": "Learn how to build a plugin for wishlist functionalities.",
"children": []
},
{
@@ -256,9 +361,6 @@ const generatedgeneratedHowToTutorialsSidebarSidebar = {
"title": "Overview",
"children": []
},
{
"type": "separator"
},
{
"loaded": true,
"isPathHref": true,
@@ -267,13 +369,10 @@ const generatedgeneratedHowToTutorialsSidebarSidebar = {
"path": "https://medusajs.com/pricing",
"children": []
},
{
"type": "separator"
},
{
"loaded": true,
"isPathHref": true,
"type": "category",
"type": "sub-category",
"title": "Self-Hosting",
"children": [
{
@@ -297,7 +396,7 @@ const generatedgeneratedHowToTutorialsSidebarSidebar = {
{
"loaded": true,
"isPathHref": true,
"type": "category",
"type": "sub-category",
"title": "Next.js Starter",
"autogenerate_path": "/deployment/storefront",
"children": [

View File

@@ -1,8 +1,4 @@
import {
generateEditedDates,
generateSidebar,
generateSplitSidebars,
} from "build-scripts"
import { generateEditedDates, generateSplitSidebars } from "build-scripts"
import { main as generateSlugChanges } from "./generate-slug-changes.mjs"
import { main as generateFilesMap } from "./generate-files-map.mjs"
import { sidebar } from "../sidebar.mjs"
@@ -11,9 +7,9 @@ async function main() {
await generateSplitSidebars({
sidebars: sidebar,
})
// await generateSlugChanges()
// await generateFilesMap()
// await generateEditedDates()
await generateSlugChanges()
await generateFilesMap()
await generateEditedDates()
}
void main()

View File

@@ -2,7 +2,6 @@
export const howToTutorialsSidebar = [
{
type: "link",
// TODO add page
path: "/how-to-tutorials",
title: "Overview",
},
@@ -17,6 +16,8 @@ export const howToTutorialsSidebar = [
{
type: "category",
title: "How-To Guides",
description:
"How-to guides are a collection of guides that help you understand how to achieve certain customizations or implementing specific features in Medusa.",
children: [
{
type: "sub-category",
@@ -24,6 +25,8 @@ export const howToTutorialsSidebar = [
autogenerate_tags: "howTo+server",
autogenerate_as_ref: true,
sort_sidebar: "alphabetize",
description:
"These how-to guides help you customize the Medusa server to implement custom features and business logic.",
},
{
type: "sub-category",
@@ -33,22 +36,29 @@ export const howToTutorialsSidebar = [
sort_sidebar: "alphabetize",
children: [
{
type: "link",
path: "/admin-components",
title: "Overview",
},
{
type: "separator",
},
{
type: "category",
title: "Layouts",
autogenerate_path: "/admin-components/layouts",
},
{
type: "category",
title: "Components",
autogenerate_path: "/admin-components/components",
type: "sidebar",
sidebar_id: "admin-components-layouts",
title: "Components & Layouts",
children: [
{
type: "link",
path: "/admin-components",
title: "Overview",
},
{
type: "separator",
},
{
type: "category",
title: "Layouts",
autogenerate_path: "/admin-components/layouts",
},
{
type: "category",
title: "Components",
autogenerate_path: "/admin-components/components",
},
],
},
],
},
@@ -57,17 +67,23 @@ export const howToTutorialsSidebar = [
{
type: "category",
title: "Tutorials",
description: `Tutorials are step-by-step guides that take you through implementing a specific use case in Medusa. You can follow these guides whether you're a beginner or an experienced Medusa developer.
While tutorials show you a specific use case, they also help you understand how to implement similar use cases in your own projects. Also, you can implement the use case in a tutorial differently to fit your business requirements.`,
children: [
{
type: "link",
title: "Custom Item Pricing",
path: "/examples/guides/custom-item-price",
description:
"Learn how to use prices from external systems for products.",
},
{
type: "link",
title: "Wishlist",
title: "Wishlist Plugin",
path: "/plugins/guides/wishlist",
description: "Learn how to build a wishlist plugin.",
description:
"Learn how to build a plugin for wishlist functionalities.",
},
{
type: "sub-category",
@@ -87,19 +103,13 @@ export const howToTutorialsSidebar = [
path: "/deployment",
title: "Overview",
},
{
type: "separator",
},
{
type: "link",
title: "Medusa Cloud",
path: "https://medusajs.com/pricing",
},
{
type: "separator",
},
{
type: "category",
type: "sub-category",
title: "Self-Hosting",
children: [
{
@@ -115,7 +125,7 @@ export const howToTutorialsSidebar = [
],
},
{
type: "category",
type: "sub-category",
title: "Next.js Starter",
autogenerate_path: "/deployment/storefront",
},

View File

@@ -135,7 +135,7 @@ async function getAutogeneratedTagSidebarItems(
)
)
return sidebarAttachCommonOptions([...(existingChildren || []), ...items])
return items
}
async function checkItem(
@@ -162,6 +162,11 @@ async function checkItem(
)}`
)
}
if (item.children) {
item.children = await checkItems(item.children)
}
if (item.autogenerate_path) {
item.children = [
...(item.children || []),
@@ -174,11 +179,14 @@ async function checkItem(
),
]
} else if (item.autogenerate_tags) {
item.children = await getAutogeneratedTagSidebarItems(
item.autogenerate_tags,
item.autogenerate_as_ref ? "ref" : "link",
item.children
)
item.children = [
...(item.children || []),
...(await getAutogeneratedTagSidebarItems(
item.autogenerate_tags,
item.autogenerate_as_ref ? "ref" : "link",
item.children
)),
]
} else if (
item.custom_autogenerate &&
Object.hasOwn(customGenerators, item.custom_autogenerate)
@@ -187,8 +195,6 @@ async function checkItem(
...(item.children || []),
...(await customGenerators[item.custom_autogenerate]()),
]
} else if (item.children) {
item.children = await checkItems(item.children)
}
item.children = sortSidebarItems({

View File

@@ -33,7 +33,8 @@ export type UseChildDocsProps = {
hideTitle?: boolean
hideDescription?: boolean
titleLevel?: number
childLevel?: number
startChildLevel?: number
endChildLevel?: number
itemsPerRow?: number
defaultItemsPerRow?: number
search?: {
@@ -51,7 +52,8 @@ export const useChildDocs = ({
hideTitle = false,
hideDescription = false,
titleLevel = 2,
childLevel = 1,
startChildLevel = 1,
endChildLevel = -1,
itemsPerRow,
defaultItemsPerRow,
search: {
@@ -60,7 +62,7 @@ export const useChildDocs = ({
...searchProps
} = { enable: false },
}: UseChildDocsProps) => {
const { shownSidebar, activeItem } = useSidebar()
const { shownSidebar, activeItem, getSidebarFirstLinkChild } = useSidebar()
const { isBrowser } = useIsBrowser()
const [searchQuery, setSearchQuery] = useState("")
const [localSearch, setLocalSearch] = useState<
@@ -135,21 +137,27 @@ export const useChildDocs = ({
)
}
const getChildrenForLevel = (
item: Sidebar.InteractiveSidebarItem,
currentLevel = 1
): Sidebar.InteractiveSidebarItem[] | undefined => {
if (currentLevel === childLevel) {
return filterNonInteractiveItems(item.children)
}
if (!item.children) {
const getChildrenForLevel = ({
item,
currentLevel = 1,
}: {
item: Sidebar.InteractiveSidebarItem
currentLevel?: number
}): Sidebar.InteractiveSidebarItem[] | undefined => {
if ((endChildLevel > 0 && currentLevel > endChildLevel) || !item.children) {
return
}
if (currentLevel >= startChildLevel) {
return filterNonInteractiveItems(item.children)
}
const childrenResult: Sidebar.InteractiveSidebarItem[] = []
filterNonInteractiveItems(item.children).forEach((child) => {
const childChildren = getChildrenForLevel(child, currentLevel + 1)
const childChildren = getChildrenForLevel({
item: child,
currentLevel: currentLevel + 1,
})
if (!childChildren) {
return
@@ -196,7 +204,7 @@ export const useChildDocs = ({
} else {
filteredItems?.forEach((item) => {
const childItems: Sidebar.SidebarItemLink[] =
(getChildrenForLevel(item)?.filter((childItem) => {
(getChildrenForLevel({ item })?.filter((childItem) => {
return isSidebarItemLink(childItem)
}) as Sidebar.SidebarItemLink[]) || []
searchableItems.push(...childItems)
@@ -283,12 +291,17 @@ export const useChildDocs = ({
)
}
const getAllLevelsElms = (
items?: Sidebar.InteractiveSidebarItem[],
headerLevel = titleLevel
) => {
const getAllLevelsElms = ({
items,
headerLevel = titleLevel,
currentLevel = 1,
}: {
items?: Sidebar.InteractiveSidebarItem[]
headerLevel?: number
currentLevel?: number
}) => {
return items?.map((item, key) => {
const itemChildren = getChildrenForLevel(item)
const itemChildren = getChildrenForLevel({ item, currentLevel })
const HeadingComponent = itemChildren?.length
? TitleHeaderComponent(headerLevel)
: undefined
@@ -315,22 +328,39 @@ export const useChildDocs = ({
</>
)}
{isChildrenCategory &&
getAllLevelsElms(itemChildren, headerLevel + 1)}
getAllLevelsElms({
items: itemChildren,
headerLevel: headerLevel + 1,
currentLevel: currentLevel + 1,
})}
{!isChildrenCategory && (
<CardList
items={
itemChildren?.map((childItem) => ({
title: childItem.title,
href: isSidebarItemLink(childItem) ? childItem.path : "",
text: childItem.description,
rightIcon:
childItem.type === "ref"
? ChevronDoubleRight
: undefined,
})) || []
itemChildren
?.filter(
(item) =>
isSidebarItemLink(item) || item.type === "sidebar"
)
.map((childItem) => {
const href = isSidebarItemLink(childItem)
? childItem.path
: getSidebarFirstLinkChild(
childItem as Sidebar.SidebarItemSidebar
)?.path
return {
title: childItem.title,
href,
text: childItem.description,
rightIcon:
childItem.type === "ref"
? ChevronDoubleRight
: undefined,
}
}) || []
}
itemsPerRow={itemsPerRow}
defaultItemsPerRow={defaultItemsPerRow}
className="mb-docs_1"
/>
)}
{key !== items.length - 1 && headerLevel === 2 && <Hr />}
@@ -398,7 +428,9 @@ export const useChildDocs = ({
<>
{onlyTopLevel
? getTopLevelElms(filteredItems)
: getAllLevelsElms(filteredItems)}
: getAllLevelsElms({
items: filteredItems,
})}
</>
)}
</>