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 -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
})
}