docs: prep for v2 documentation (#6710)

This PR includes documentation that preps for v2 docs (but doesn't introduce new docs).

_Note: The number of file changes in the PR is due to find-and-replace within the `references` which is unavoidable. Let me know if I should move it to another PR._

## Changes

- Change Medusa version in base OAS used for v2.
- Fix to docblock generator related to not catching all path parameters.
- Added typedoc plugin that generates ER Diagrams, which will be used specifically for data model references in commerce modules.
- Changed OAS tool to output references in `www/apps/api-reference/specs-v2` directory when the `--v2` option is used.
- Added a version switcher to the API reference to switch between V1 and V2. This switcher is enabled by an environment variable, so it won't be visible/usable at the moment.
- Upgraded docusaurus to v3.0.1
- Added new Vale rules to ensure correct spelling of Medusa Admin and module names.
- Added new components to the `docs-ui` package that will be used in future documentation changes.
This commit is contained in:
Shahed Nasser
2024-03-18 09:47:35 +02:00
committed by GitHub
parent 56a6ec0227
commit bb87db8342
2008 changed files with 15716 additions and 10536 deletions

View File

@@ -11,4 +11,5 @@ NEXT_PUBLIC_UI_URL=
ALGOLIA_WRITE_API_KEY=
NEXT_PUBLIC_AI_ASSISTANT_URL=
NEXT_PUBLIC_AI_WEBSITE_ID=
NEXT_PUBLIC_AI_API_ASSISTANT_RECAPTCHA_SITE_KEY=
NEXT_PUBLIC_AI_API_ASSISTANT_RECAPTCHA_SITE_KEY=
NEXT_PUBLIC_VERSIONING=

View File

@@ -7,5 +7,5 @@ module.exports = {
next: {
rootDir: ".",
},
},
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,4 +1,4 @@
import { CodeTabs } from "docs-ui"
import { CodeTabs, CodeTab } from "docs-ui"
import Space from "@/components/Space"
import DownloadFull from "@/components/DownloadFull"
@@ -10,26 +10,22 @@ Check out the [quickstart guide](https://docs.medusajs.com/create-medusa-app).
### Client Libraries
<CodeTabs
tabs={[
{
label: 'Medusa JS Client',
value: 'js-client',
code: {
source: `npm install @medusajs/medusa-js`,
lang: `bash`,
}
},
{
label: 'Medusa React',
value: 'medusa-react',
code: {
source: `npm install medusa-react @tanstack/react-query @medusajs/medusa`,
lang: `bash`,
}
}
]}
/>
<CodeTabs group="clients">
<CodeTab label="Medusa JS Client" value="js-client">
```bash
npm install @medusajs/medusa-js
```
</CodeTab>
<CodeTab label="Medusa React" value="medusa-react">
```bash
npm install medusa-react @tanstack/react-query @medusajs/medusa
```
</CodeTab>
</CodeTabs>
### Download Full Reference

File diff suppressed because it is too large Load Diff

View File

@@ -1,10 +1,9 @@
import clsx from "clsx"
import "../../../css/globals.css"
import "../../globals.css"
import Navbar from "@/components/Navbar"
import { Inter } from "next/font/google"
import { Roboto_Mono } from "next/font/google"
import Providers from "../../../providers"
import { Sidebar } from "docs-ui"
import { WideLayout } from "docs-ui"
import { Inter, Roboto_Mono } from "next/font/google"
import clsx from "clsx"
export const metadata = {
title: "Medusa API Reference",
@@ -28,31 +27,12 @@ export default function RootLayout({
children: React.ReactNode
}) {
return (
<html lang="en" className={clsx("h-full w-full")}>
<body
className={clsx(
inter.variable,
robotoMono.variable,
"bg-docs-bg font-base text-medium w-full",
"text-medusa-fg-subtle",
"h-screen overflow-hidden"
)}
>
<Providers>
<Navbar />
<div
className="w-full h-[calc(100%-57px)] overflow-y-scroll overflow-x-hidden"
id="main"
>
<div className="max-w-xxl mx-auto flex w-full px-1.5">
<Sidebar />
<main className="lg:w-ref-main relative mt-4 w-full flex-1 lg:mt-7">
{children}
</main>
</div>
</div>
</Providers>
</body>
</html>
<WideLayout
ProvidersComponent={Providers}
NavbarComponent={Navbar}
bodyClassName={clsx(inter.variable, robotoMono.variable)}
>
{children}
</WideLayout>
)
}

View File

@@ -8,6 +8,7 @@ import type { Area } from "@/types/openapi"
import DividedLayout from "@/layouts/Divided"
import { capitalize } from "docs-ui"
import PageTitleProvider from "../../../providers/page-title"
import PageHeading from "../../../components/PageHeading"
type ReferencePageProps = {
params: {
@@ -19,15 +20,11 @@ const ReferencePage = async ({ params: { area } }: ReferencePageProps) => {
return (
<AreaProvider area={area}>
<PageTitleProvider>
<h1 className="!text-h2 block lg:hidden">
Medusa {capitalize(area)} API Reference
</h1>
<PageHeading className="!text-h2 block lg:hidden" />
<DividedLayout
mainContent={
<Section>
<h1 className="!text-h2 hidden lg:block">
Medusa {capitalize(area)} API Reference
</h1>
<PageHeading className="!text-h2 hidden lg:block" />
{area.includes("admin") && <AdminDescription />}
{area.includes("store") && <StoreDescription />}
</Section>

View File

@@ -2,11 +2,15 @@ import { NextResponse } from "next/server"
import path from "path"
import OpenAPIParser from "@readme/openapi-parser"
import getPathsOfTag from "@/utils/get-paths-of-tag"
import type { ExpandedDocument } from "@/types/openapi"
import type { ExpandedDocument, Version } from "@/types/openapi"
export async function GET(request: Request) {
const { searchParams } = new URL(request.url)
const area = searchParams.get("area")
const version =
process.env.NEXT_PUBLIC_VERSIONING === "true"
? (searchParams.get("version") as Version) || "1"
: "1"
const expand = searchParams.get("expand")
if (area !== "admin" && area !== "store") {
return NextResponse.json(
@@ -20,7 +24,11 @@ export async function GET(request: Request) {
)
}
const baseSpecs = (await OpenAPIParser.parse(
path.join(process.cwd(), `specs/${area}/openapi.yaml`)
path.join(
process.cwd(),
version === "1" ? "specs" : "specs-v2",
`${area}/openapi.yaml`
)
)) as ExpandedDocument
if (expand) {

View File

@@ -1,11 +1,16 @@
import { NextResponse } from "next/server"
import path from "path"
import getPathsOfTag from "@/utils/get-paths-of-tag"
import { Version } from "../../../types/openapi"
export async function GET(request: Request) {
const { searchParams } = new URL(request.url)
const tagName = searchParams.get("tagName") || ""
const area = searchParams.get("area")
const version =
process.env.NEXT_PUBLIC_VERSIONING === "true"
? (searchParams.get("version") as Version) || "1"
: "1"
if (area !== "admin" && area !== "store") {
return NextResponse.json(
@@ -26,9 +31,15 @@ export async function GET(request: Request) {
path.join(process.cwd(), "specs/store/code_samples")
path.join(process.cwd(), "specs/store/components")
path.join(process.cwd(), "specs/store/paths")
path.join(process.cwd(), "specs-v2/admin/code_samples")
path.join(process.cwd(), "specs-v2/admin/components")
path.join(process.cwd(), "specs-v2/admin/paths")
path.join(process.cwd(), "specs-v2/store/code_samples")
path.join(process.cwd(), "specs-v2/store/components")
path.join(process.cwd(), "specs-v2/store/paths")
// get path files
const paths = await getPathsOfTag(tagName, area)
const paths = await getPathsOfTag(tagName, area, version)
return NextResponse.json(
{

View File

@@ -1,14 +1,14 @@
import { MetadataRoute } from "next"
import OpenAPIParser from "@readme/openapi-parser"
import path from "path"
import getBaseUrl from "../../utils/get-base-url"
import type { ExpandedDocument, Operation } from "../../types/openapi"
import getUrl from "../../utils/get-url"
import getSectionId from "../../utils/get-section-id"
import getPathsOfTag from "../../utils/get-paths-of-tag"
import { config } from "../../config"
export default async function sitemap(): Promise<MetadataRoute.Sitemap> {
const baseUrl = getBaseUrl()
const baseUrl = config.baseUrl
const results = [
{

View File

@@ -2,7 +2,7 @@ import type { MDXComponents } from "mdx/types"
import Security from "./Security"
import type { OpenAPIV3 } from "openapi-types"
import H2 from "./H2"
import { CodeMdx, Kbd, NextLink } from "docs-ui"
import { Link, MDXComponents as UiMDXComponents } from "docs-ui"
export type ScopeType = {
specs?: OpenAPIV3.Document
@@ -11,11 +11,12 @@ export type ScopeType = {
const getCustomComponents = (scope?: ScopeType): MDXComponents => {
return {
...UiMDXComponents,
Security: () => <Security specs={scope?.specs} />,
code: CodeMdx,
a: NextLink,
h2: (props) => <H2 addToSidebar={scope?.addToSidebar} {...props} />,
kbd: Kbd,
a: Link,
h2: (props: React.HTMLAttributes<HTMLHeadingElement>) => (
<H2 addToSidebar={scope?.addToSidebar} {...props} />
),
}
}

View File

@@ -20,6 +20,9 @@ const MDXContentServer = ({ content, ...props }: MDXContentServerProps) => {
components={getCustomComponents((props.scope as ScopeType) || {})}
options={{
scope: props.scope,
mdxOptions: {
development: process.env.NEXT_PUBLIC_ENV === "development",
},
}}
{...props}
/>

View File

@@ -1,47 +1,48 @@
"use client"
import { Navbar as UiNavbar, usePageLoading } from "docs-ui"
import getLinkWithBasePath from "../../utils/get-link-with-base-path"
import { useSidebar } from "docs-ui"
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"
const Navbar = () => {
const { setMobileSidebarOpen, mobileSidebarOpen } = useSidebar()
const pathname = usePathname()
const { isLoading } = usePageLoading()
const navbarItems = useMemo(
() =>
getNavbarItems({
basePath: config.baseUrl,
activePath: pathname,
}),
[pathname]
)
return (
<UiNavbar
logo={{
light: "/images/logo-icon.png",
dark: "/images/logo-icon-dark.png",
}}
items={[
{
href: `/`,
label: "Docs",
},
{
href: `/user-guide`,
label: "User Guide",
},
{
href: `${getLinkWithBasePath("/store")}`,
label: "Store API",
},
{
href: `${getLinkWithBasePath("/admin")}`,
label: "Admin API",
},
{
href: `/ui`,
label: "UI",
},
]}
items={navbarItems}
mobileMenuButton={{
setMobileSidebarOpen,
mobileSidebarOpen,
}}
additionalActions={<FeedbackModal />}
additionalActionsBefore={
<>
{process.env.NEXT_PUBLIC_VERSIONING === "true" && <VersionSwitcher />}
</>
}
additionalActionsAfter={<FeedbackModal />}
isLoading={isLoading}
/>
)

View File

@@ -0,0 +1,25 @@
"use client"
import { capitalize } from "docs-ui"
import { useArea } from "../../providers/area"
import { useVersion } from "../../providers/version"
type PageHeadingProps = {
className?: string
}
const PageHeading = ({ className }: PageHeadingProps) => {
const { area } = useArea()
const { version } = useVersion()
const versionText =
process.env.NEXT_PUBLIC_VERSIONING === "true" ? ` V${version}` : ""
return (
<h1 className={className}>
Medusa{versionText} {capitalize(area)} API Reference
</h1>
)
}
export default PageHeading

View File

@@ -1,5 +1,5 @@
import type { Code } from "@/types/openapi"
import { CodeTabs } from "docs-ui"
import { LegacyCodeTabs } from "docs-ui"
import slugify from "slugify"
export type TagOperationCodeSectionRequestSamplesProps = {
@@ -12,7 +12,7 @@ const TagOperationCodeSectionRequestSamples = ({
return (
<div>
<h3>Request samples</h3>
<CodeTabs
<LegacyCodeTabs
tabs={codeSamples.map((codeSample) => ({
label: codeSample.label,
value: slugify(codeSample.label),

View File

@@ -8,7 +8,7 @@ import dynamic from "next/dynamic"
import TagsOperationDescriptionSectionParameters from "./Parameters"
import MDXContentClient from "@/components/MDXContent/Client"
import { useArea } from "../../../../providers/area"
import { Feedback, Badge, NextLink, FeatureFlagNotice } from "docs-ui"
import { Feedback, Badge, Link, FeatureFlagNotice } from "docs-ui"
import { usePathname } from "next/navigation"
import formatReportLink from "../../../../utils/format-report-link"
@@ -70,9 +70,9 @@ const TagsOperationDescriptionSection = ({
{operation.externalDocs && (
<>
Related guide:{" "}
<NextLink href={operation.externalDocs.url} target="_blank">
<Link href={operation.externalDocs.url} target="_blank">
{operation.externalDocs.description || "Read More"}
</NextLink>
</Link>
</>
)}
{operation.security && (

View File

@@ -1,4 +1,4 @@
import { Badge, NextLink, Tooltip } from "docs-ui"
import { Badge, Link, Tooltip } from "docs-ui"
export type TagsOperationFeatureFlagNoticeProps = {
featureFlag: string
@@ -19,12 +19,12 @@ const TagsOperationFeatureFlagNotice = ({
<span className={tooltipTextClassName}>
To use this {type}, make sure to
<br />
<NextLink
<Link
href="https://docs.medusajs.com/development/feature-flags/toggle"
target="__blank"
>
enable its feature flag: <code>{featureFlag}</code>
</NextLink>
</Link>
</span>
}
clickable

View File

@@ -3,7 +3,7 @@ import type { SchemaObject } from "@/types/openapi"
import clsx from "clsx"
import dynamic from "next/dynamic"
import { Fragment } from "react"
import { NextLink, type InlineCodeProps, capitalize } from "docs-ui"
import { Link, type InlineCodeProps, capitalize } from "docs-ui"
const InlineCode = dynamic<InlineCodeProps>(
async () => (await import("docs-ui")).InlineCode
@@ -122,9 +122,9 @@ const TagOperationParametersDescription = ({
{schema.externalDocs && (
<>
Related guide:{" "}
<NextLink href={schema.externalDocs.url} target="_blank">
<Link href={schema.externalDocs.url} target="_blank">
{schema.externalDocs.description || "Read More"}
</NextLink>
</Link>
</>
)}
</div>

View File

@@ -1,11 +1,5 @@
import type { SchemaObject } from "@/types/openapi"
import dynamic from "next/dynamic"
import type { TooltipProps } from "docs-ui"
import { Badge, ExpandableNotice, FeatureFlagNotice, NextLink } from "docs-ui"
const Tooltip = dynamic<TooltipProps>(
async () => (await import("docs-ui")).Tooltip
) as React.FC<TooltipProps>
import { Badge, ExpandableNotice, FeatureFlagNotice } from "docs-ui"
export type TagOperationParametersNameProps = {
name: string
@@ -37,7 +31,7 @@ const TagOperationParametersName = ({
<br />
<FeatureFlagNotice
featureFlag={schema["x-featureFlag"]}
type="parameter"
type="type"
/>
</>
)}

View File

@@ -4,22 +4,18 @@ import getSectionId from "@/utils/get-section-id"
import type { OpenAPIV3 } from "openapi-types"
import useSWR from "swr"
import type { Operation, PathsObject } from "@/types/openapi"
import {
SidebarItemSections,
useSidebar,
type SidebarItemType,
swrFetcher,
} from "docs-ui"
import { useSidebar, swrFetcher, getLinkWithBasePath } from "docs-ui"
import { Fragment, useEffect, useMemo } from "react"
import dynamic from "next/dynamic"
import type { TagOperationProps } from "../Operation"
import { useArea } from "@/providers/area"
import getLinkWithBasePath from "@/utils/get-link-with-base-path"
import clsx from "clsx"
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 { useVersion } from "../../../providers/version"
const TagOperation = dynamic<TagOperationProps>(
async () => import("../Operation")
@@ -32,6 +28,7 @@ export type TagPathsProps = {
const TagPaths = ({ tag, className }: TagPathsProps) => {
const tagSlugName = useMemo(() => getSectionId([tag.name]), [tag])
const { area } = useArea()
const { version } = useVersion()
const { items, addItems, findItemInSection } = useSidebar()
const { baseSpecs } = useBaseSpecs()
const { loading } = useLoading()
@@ -47,7 +44,10 @@ const TagPaths = ({ tag, className }: TagPathsProps) => {
paths: PathsObject
}>(
!Object.keys(paths).length
? getLinkWithBasePath(`/tag?tagName=${tagSlugName}&area=${area}`)
? getLinkWithBasePath(
`/tag?tagName=${tagSlugName}&area=${area}&version=${version}`,
process.env.NEXT_PUBLIC_BASE_PATH
)
: null,
swrFetcher,
{

View File

@@ -15,7 +15,7 @@ import SectionContainer from "../../Section/Container"
import { useArea } from "../../../providers/area"
import SectionDivider from "../../Section/Divider"
import clsx from "clsx"
import { Feedback, Loading, NextLink } from "docs-ui"
import { Feedback, Loading, Link } from "docs-ui"
import { usePathname } from "next/navigation"
import formatReportLink from "../../../utils/format-report-link"
@@ -100,9 +100,9 @@ const TagSection = ({ tag }: TagSectionProps) => {
{tag.externalDocs && (
<>
Related guide:{" "}
<NextLink href={tag.externalDocs.url} target="_blank">
<Link href={tag.externalDocs.url} target="_blank">
{tag.externalDocs.description || "Read More"}
</NextLink>
</Link>
</>
)}
<Feedback

View File

@@ -7,11 +7,12 @@ import { useBaseSpecs } from "@/providers/base-specs"
import dynamic from "next/dynamic"
import type { TagSectionProps } from "./Section"
import { useArea } from "@/providers/area"
import getLinkWithBasePath from "@/utils/get-link-with-base-path"
import { SidebarItemSections, swrFetcher, useSidebar } from "docs-ui"
import { swrFetcher, useSidebar, getLinkWithBasePath } 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 { useVersion } from "../../providers/version"
const TagSection = dynamic<TagSectionProps>(
async () => import("./Section")
@@ -32,10 +33,14 @@ const Tags = () => {
const { baseSpecs, setBaseSpecs } = useBaseSpecs()
const { addItems } = useSidebar()
const { area } = useArea()
const { version } = useVersion()
const { data } = useSWR<ExpandedDocument>(
loadData && !baseSpecs
? getLinkWithBasePath(`/base-specs?area=${area}&expand=${expand}`)
? getLinkWithBasePath(
`/base-specs?area=${area}&expand=${expand}&version=${version}`,
process.env.NEXT_PUBLIC_BASE_PATH
)
: null,
swrFetcher,
{

View File

@@ -0,0 +1,22 @@
"use client"
import { Note } from "docs-ui"
import { useVersion } from "../../providers/version"
const VersionNote = () => {
const { version } = useVersion()
return (
<>
{version === "2" && (
<Note type="warning" title="Production Warning">
Medusa v2.0 is in development and not suitable for production
environments. As such, the API reference is incomplete and subject to
change, so please use it with caution.
</Note>
)}
</>
)
}
export default VersionNote

View File

@@ -0,0 +1,36 @@
"use client"
import { Toggle } from "docs-ui"
import { useVersion } from "../../providers/version"
import clsx from "clsx"
const VersionSwitcher = () => {
const { version, changeVersion } = useVersion()
return (
<div className="flex gap-0.5 justify-center items-center">
<span
className={clsx(
version === "1" && "text-medusa-fg-subtle",
version === "2" && "text-medusa-fg-disabled"
)}
>
V1
</span>
<Toggle
checked={version === "2"}
onCheckedChange={(checked) => changeVersion(checked ? "2" : "1")}
/>
<span
className={clsx(
version === "1" && "text-medusa-fg-disabled",
version === "2" && "text-medusa-fg-subtle"
)}
>
V2
</span>
</div>
)
}
export default VersionSwitcher

View File

@@ -0,0 +1,18 @@
import { DocsConfig } from "types"
import { mobileSidebarItems } from "docs-ui"
export const config: DocsConfig = {
baseUrl: process.env.NEXT_PUBLIC_BASE_URL || "http://localhost:3000",
// sidebar is auto generated
sidebar: {
top: [
{
title: "Introduction",
path: "",
loaded: true,
},
],
bottom: [],
mobile: mobileSidebarItems,
},
}

View File

@@ -33,6 +33,7 @@ const withMDX = mdx({
extension: /\.mdx?$/,
options: {
rehypePlugins: [],
development: process.env.NODE_ENV === "development",
},
})

View File

@@ -7,21 +7,23 @@
"dev:monorepo": "yarn dev -p 3000",
"build": "next build",
"build:dev": "NODE_ENV=test next build",
"build:prod": "NEXT_PUBLIC_ENV=production next build",
"start": "next start",
"start:monorepo": "yarn start -p 3000",
"lint": "next lint --fix"
},
"dependencies": {
"@mdx-js/loader": "^2.3.0",
"@mdx-js/react": "^2.3.0",
"@mdx-js/loader": "^3.0.0",
"@mdx-js/react": "^3.0.0",
"@medusajs/icons": "^1.2.0",
"@next/mdx": "13.4.19",
"@medusajs/ui": "^2.4.1",
"@next/mdx": "14.1.3",
"@readme/openapi-parser": "^2.5.0",
"@types/mapbox__rehype-prism": "^0.8.0",
"@types/mdx": "^2.0.5",
"@types/node": "20.4.5",
"@types/react": "18.2.17",
"@types/react-dom": "18.2.7",
"@types/react": "^18.2.0",
"@types/react-dom": "^18.2.0",
"@types/react-transition-group": "^4.4.6",
"autoprefixer": "10.4.14",
"clsx": "^2.0.0",
@@ -30,14 +32,14 @@
"jsdom": "^22.1.0",
"json-schema": "^0.4.0",
"json-stringify-pretty-compact": "^4.0.0",
"next": "^14",
"next": "^14.1.3",
"next-mdx-remote": "^4.4.1",
"openapi-sampler": "^1.3.1",
"openapi-types": "^12.1.3",
"postcss": "8.4.27",
"prism-react-renderer": "2.3.1",
"react": "latest",
"react-dom": "latest",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-instantsearch": "^7.0.1",
"react-intersection-observer": "^9.5.3",
"react-tooltip": "^5.19.0",
@@ -50,8 +52,9 @@
"yaml": "^2.3.1"
},
"devDependencies": {
"@next/bundle-analyzer": "^13.4.19",
"@types/jsdom": "^21.1.1"
"@next/bundle-analyzer": "^14.1.3",
"@types/jsdom": "^21.1.1",
"types": "*"
},
"engines": {
"node": ">=18.17.0"

View File

@@ -1,74 +0,0 @@
"use client"
import {
createContext,
useCallback,
useContext,
useEffect,
useState,
} from "react"
type ColorMode = "light" | "dark"
type ColorModeContextType = {
colorMode: ColorMode
setColorMode: (value: ColorMode) => void
toggleColorMode: () => void
}
const ColorModeContext = createContext<ColorModeContextType | null>(null)
type ColorModeProviderProps = {
children: React.ReactNode
}
const ColorModeProvider = ({ children }: ColorModeProviderProps) => {
const [colorMode, setColorMode] = useState<ColorMode>("light")
const toggleColorMode = () =>
setColorMode(colorMode === "light" ? "dark" : "light")
const init = () => {
const theme = localStorage.getItem("theme")
if (theme && (theme === "light" || theme === "dark")) {
setColorMode(theme)
}
}
useEffect(() => {
init()
}, [])
useEffect(() => {
const theme = localStorage.getItem("theme")
if (theme !== colorMode) {
localStorage.setItem("theme", colorMode)
}
document.querySelector("html")?.setAttribute("data-theme", colorMode)
}, [colorMode])
return (
<ColorModeContext.Provider
value={{
colorMode,
setColorMode,
toggleColorMode,
}}
>
{children}
</ColorModeContext.Provider>
)
}
export default ColorModeProvider
export const useColorMode = (): ColorModeContextType => {
const context = useContext(ColorModeContext)
if (!context) {
throw new Error("useColorMode must be used inside a ColorModeProvider")
}
return context
}

View File

@@ -1,18 +1,17 @@
"use client"
import {
AiAssistantProvider,
AnalyticsProvider,
ColorModeProvider,
MobileProvider,
ModalProvider,
NavbarProvider,
PageLoadingProvider,
ScrollControllerProvider,
} from "docs-ui"
import BaseSpecsProvider from "./base-specs"
import SidebarProvider from "./sidebar"
import SearchProvider from "./search"
import VersionProvider from "./version"
type ProvidersProps = {
children?: React.ReactNode
@@ -27,11 +26,11 @@ const Providers = ({ children }: ProvidersProps) => {
<BaseSpecsProvider>
<ScrollControllerProvider scrollableSelector="#main">
<SidebarProvider>
<NavbarProvider>
<SearchProvider>
<MobileProvider>{children}</MobileProvider>
</SearchProvider>
</NavbarProvider>
<SearchProvider>
<MobileProvider>
<VersionProvider>{children}</VersionProvider>
</MobileProvider>
</SearchProvider>
</SidebarProvider>
</ScrollControllerProvider>
</BaseSpecsProvider>

View File

@@ -5,8 +5,9 @@ import {
SearchProvider as UiSearchProvider,
AiAssistantCommandIcon,
AiAssistantProvider,
searchFilters,
} from "docs-ui"
import getBaseUrl from "../utils/get-base-url"
import { config } from "../config"
type SearchProviderProps = {
children: React.ReactNode
@@ -29,47 +30,30 @@ const SearchProvider = ({ children }: SearchProviderProps) => {
isLoading,
suggestions: [
{
title: "Search Suggestions",
title: "Getting started? Try one of the following terms.",
items: [
"Authentication",
"Expanding fields",
"Selecting fields",
"Pagination",
"Query parameter types",
"Install Medusa with create-medusa-app",
"Next.js quickstart",
"Admin dashboard quickstart",
"Commerce modules",
"Medusa architecture",
],
},
{
title: "Developing with Medusa",
items: [
"Recipes",
"How to create API routes",
"How to create an entity",
"How to create a plugin",
"How to create an admin widget",
],
},
],
checkInternalPattern: new RegExp(`^${getBaseUrl()}/api/(admin|store)`),
filterOptions: [
{
value: "admin",
label: "Admin API",
},
{
value: "store",
label: "Store API",
},
{
value: "docs",
label: "Docs",
},
{
value: "user-guide",
label: "User Guide",
},
{
value: "plugins",
label: "Plugins",
},
{
value: "reference",
label: "References",
},
{
value: "ui",
label: "UI",
},
],
checkInternalPattern: new RegExp(
`^${config.baseUrl}/api/(admin|store)`
),
filterOptions: searchFilters,
}}
commands={[
{

View File

@@ -1,9 +1,11 @@
"use client"
import {
SidebarProvider as UiSidebarProvider,
mobileSidebarItems,
usePageLoading,
useScrollController,
} from "docs-ui"
import { config } from "../config"
type SidebarProviderProps = {
children?: React.ReactNode
@@ -19,42 +21,7 @@ const SidebarProvider = ({ children }: SidebarProviderProps) => {
setIsLoading={setIsLoading}
shouldHandleHashChange={true}
scrollableElement={scrollableElement}
initialItems={{
top: [
{
title: "Introduction",
path: "",
loaded: true,
},
],
bottom: [],
mobile: [
{
title: "Docs",
path: "https://docs.medusajs.com/",
loaded: true,
isPathHref: true,
},
{
title: "User Guide",
path: "https://docs.medusajs.com/user-guide",
loaded: true,
isPathHref: true,
},
{
title: "Store API",
path: "/api/store",
loaded: true,
isPathHref: true,
},
{
title: "Admin API",
path: "/api/admin",
loaded: true,
isPathHref: true,
},
],
}}
initialItems={config.sidebar}
>
{children}
</UiSidebarProvider>

View File

@@ -0,0 +1,74 @@
"use client"
import { createContext, useContext, useEffect, useState } from "react"
import { Version } from "../types/openapi"
import { usePathname } from "next/navigation"
import { useIsBrowser } from "docs-ui"
type VersionContextType = {
version: Version
changeVersion: (value: Version) => void
}
const VersionContext = createContext<VersionContextType | null>(null)
type VersionProviderProps = {
children: React.ReactNode
}
const VersionProvider = ({ children }: VersionProviderProps) => {
const pathname = usePathname()
const [version, setVersion] = useState<Version>("1")
const isBrowser = useIsBrowser()
const changeVersion = (version: Version) => {
if (!isBrowser || process.env.NEXT_PUBLIC_VERSIONING !== "true") {
return
}
localStorage.setItem("api-version", version)
location.href = `${location.href.substring(
0,
location.href.indexOf(location.pathname)
)}${pathname}`
}
useEffect(() => {
if (!isBrowser || process.env.NEXT_PUBLIC_VERSIONING !== "true") {
return
}
// try to load from localstorage
const versionInLocalStorage = localStorage.getItem("api-version") as Version
if (versionInLocalStorage) {
setVersion(versionInLocalStorage)
}
}, [isBrowser])
useEffect(() => {
if (!isBrowser || process.env.NEXT_PUBLIC_VERSIONING !== "true") {
return
}
const versionInLocalStorage = localStorage.getItem("api-version") as Version
if (version !== versionInLocalStorage) {
localStorage.setItem("api-version", version)
}
}, [version, isBrowser])
return (
<VersionContext.Provider value={{ version, changeVersion }}>
{children}
</VersionContext.Provider>
)
}
export default VersionProvider
export const useVersion = (): VersionContextType => {
const context = useContext(VersionContext)
if (!context) {
throw new Error("useVersion must be used inside an VersionProvider")
}
return context
}

View File

@@ -1,6 +1,7 @@
import type { OpenAPIV3 } from "openapi-types"
export type Area = "admin" | "store"
export type Version = "1" | "2"
export type Code = {
lang: string

View File

@@ -1,3 +0,0 @@
export default function getBaseUrl() {
return process.env.NEXT_PUBLIC_BASE_URL || "http://localhost:3000"
}

View File

@@ -1,3 +0,0 @@
export default function getLinkWithBasePath(path: string): string {
return `${process.env.NEXT_PUBLIC_BASE_PATH || "/api"}${path}`
}

View File

@@ -1,7 +1,7 @@
import path from "path"
import { promises as fs } from "fs"
import type { OpenAPIV3 } from "openapi-types"
import type { Operation, Document } from "@/types/openapi"
import type { Operation, Document, Version } from "@/types/openapi"
import readSpecDocument from "./read-spec-document"
import getSectionId from "./get-section-id"
import OpenAPIParser from "@readme/openapi-parser"
@@ -12,10 +12,15 @@ type ParsedPathItemObject = OpenAPIV3.PathItemObject<Operation> & {
export default async function getPathsOfTag(
tagName: string,
area: string
area: string,
version: Version = "1"
): Promise<Document> {
// get path files
const basePath = path.join(process.cwd(), `specs/${area}/paths`)
const basePath = path.join(
process.cwd(),
version === "1" ? "specs" : "specs-v2",
`${area}/paths`
)
const files = await fs.readdir(basePath)

View File

@@ -1,4 +1,4 @@
import type { SidebarItemType } from "docs-ui"
import type { SidebarItemType } from "types"
import type { Operation, PathsObject } from "@/types/openapi"
import type { OpenAPIV3 } from "openapi-types"
import dynamic from "next/dynamic"

View File

@@ -1,5 +1,5 @@
import getBaseUrl from "./get-base-url"
import { config } from "../config"
export default function getUrl(area: string, tagName?: string): string {
return `${getBaseUrl()}/api/${area}#${tagName}`
return `${config.baseUrl}/api/${area}#${tagName}`
}