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:
@@ -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=
|
||||
@@ -7,5 +7,5 @@ module.exports = {
|
||||
next: {
|
||||
rootDir: ".",
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -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
@@ -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>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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(
|
||||
{
|
||||
|
||||
@@ -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 = [
|
||||
{
|
||||
|
||||
@@ -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} />
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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}
|
||||
/>
|
||||
|
||||
@@ -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}
|
||||
/>
|
||||
)
|
||||
|
||||
25
www/apps/api-reference/components/PageHeading/index.tsx
Normal file
25
www/apps/api-reference/components/PageHeading/index.tsx
Normal 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
|
||||
@@ -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),
|
||||
|
||||
@@ -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 && (
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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"
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
|
||||
@@ -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,
|
||||
{
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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,
|
||||
{
|
||||
|
||||
22
www/apps/api-reference/components/VersionNote/index.tsx
Normal file
22
www/apps/api-reference/components/VersionNote/index.tsx
Normal 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
|
||||
36
www/apps/api-reference/components/VersionSwitcher/index.tsx
Normal file
36
www/apps/api-reference/components/VersionSwitcher/index.tsx
Normal 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
|
||||
18
www/apps/api-reference/config/index.ts
Normal file
18
www/apps/api-reference/config/index.ts
Normal 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,
|
||||
},
|
||||
}
|
||||
@@ -33,6 +33,7 @@ const withMDX = mdx({
|
||||
extension: /\.mdx?$/,
|
||||
options: {
|
||||
rehypePlugins: [],
|
||||
development: process.env.NODE_ENV === "development",
|
||||
},
|
||||
})
|
||||
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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
|
||||
}
|
||||
@@ -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>
|
||||
|
||||
@@ -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={[
|
||||
{
|
||||
|
||||
@@ -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>
|
||||
|
||||
74
www/apps/api-reference/providers/version.tsx
Normal file
74
www/apps/api-reference/providers/version.tsx
Normal 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
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
export default function getBaseUrl() {
|
||||
return process.env.NEXT_PUBLIC_BASE_URL || "http://localhost:3000"
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
export default function getLinkWithBasePath(path: string): string {
|
||||
return `${process.env.NEXT_PUBLIC_BASE_PATH || "/api"}${path}`
|
||||
}
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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}`
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user