Files
medusa-store/www/packages/docs-ui/src/components/CodeBlock/index.tsx
Shahed Nasser bb87db8342 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.
2024-03-18 07:47:35 +00:00

330 lines
10 KiB
TypeScript

"use client"
import React, { useMemo, useState } from "react"
import clsx from "clsx"
import { HighlightProps, Highlight, themes } from "prism-react-renderer"
import { CopyButton, Tooltip, LegacyLink } from "@/components"
import { useColorMode } from "@/providers"
import { ExclamationCircle, PlaySolid, SquareTwoStack } from "@medusajs/icons"
import { CodeBlockHeader, CodeBlockHeaderMeta } from "./Header"
import { CodeBlockLine } from "./Line"
import { ApiAuthType, ApiDataOptions, ApiMethod } from "types"
import { CSSTransition } from "react-transition-group"
import { ApiRunner } from "./ApiRunner"
import { GITHUB_ISSUES_PREFIX } from "../.."
export type Highlight = {
line: number
text?: string
tooltipText?: string
}
export type CodeBlockMetaFields = {
title?: string
npm2yarn?: boolean
highlights?: string[][]
apiTesting?: boolean
testApiMethod?: ApiMethod
testApiUrl?: string
testAuthType?: ApiAuthType
testPathParams?: ApiDataOptions
testQueryParams?: ApiDataOptions
testBodyParams?: ApiDataOptions
noCopy?: boolean
noReport?: boolean
noLineNumbers?: boolean
} & CodeBlockHeaderMeta
export type CodeBlockStyle = "loud" | "subtle"
export type CodeBlockProps = {
source: string
lang?: string
className?: string
collapsed?: boolean
blockStyle?: CodeBlockStyle
children?: React.ReactNode
} & CodeBlockMetaFields &
Omit<HighlightProps, "code" | "language" | "children">
export const CodeBlock = ({
source,
lang = "",
className,
collapsed = false,
title = "",
highlights = [],
apiTesting = false,
blockStyle = "loud",
noCopy = false,
noReport = false,
noLineNumbers = false,
children,
...rest
}: CodeBlockProps) => {
if (!source && typeof children === "string") {
source = children
}
const { colorMode } = useColorMode()
const [showTesting, setShowTesting] = useState(false)
const canShowApiTesting = useMemo(
() => apiTesting && rest.testApiMethod && rest.testApiUrl,
[apiTesting, rest]
)
const bgColor = useMemo(
() =>
clsx(
blockStyle === "loud" && [
colorMode === "light" && "bg-medusa-code-bg-base",
colorMode === "dark" && "bg-medusa-bg-component",
],
blockStyle === "subtle" && [
colorMode === "light" && "bg-medusa-bg-subtle",
colorMode === "dark" && "bg-medusa-code-bg-base",
]
),
[blockStyle, colorMode]
)
const lineNumbersColor = useMemo(
() =>
clsx(
blockStyle === "loud" && [
colorMode === "light" && "text-medusa-code-text-subtle",
colorMode === "dark" && "text-medusa-fg-muted",
],
blockStyle === "subtle" && [
colorMode === "light" && "text-medusa-fg-muted",
colorMode === "dark" && "text-medusa-code-text-subtle",
]
),
[blockStyle, colorMode]
)
const borderColor = useMemo(
() =>
clsx(
blockStyle === "loud" && [
colorMode === "light" && "border-medusa-code-border",
colorMode === "dark" && "border-medusa-border-base",
],
blockStyle === "subtle" && [
colorMode === "light" && "border-medusa-border-base",
colorMode === "dark" && "border-medusa-code-border",
]
),
[blockStyle, colorMode]
)
const iconColor = useMemo(
() =>
clsx(
blockStyle === "loud" && [
colorMode === "light" && "text-medusa-code-icon",
colorMode === "dark" && "text-medusa-fg-muted",
],
blockStyle === "subtle" && [
colorMode === "light" && "text-medusa-fg-muted",
colorMode === "dark" && "text-medusa-code-icon",
]
),
[blockStyle, colorMode]
)
if (!source.length) {
return <></>
}
const transformedHighlights: Highlight[] = highlights
.filter((highlight) => highlight.length !== 0)
.map((highlight) => ({
line: parseInt(highlight[0]),
text: highlight.length >= 2 ? highlight[1] : undefined,
tooltipText: highlight.length >= 3 ? highlight[2] : undefined,
}))
return (
<>
{title && (
<CodeBlockHeader
title={title}
blockStyle={blockStyle}
badgeLabel={rest.badgeLabel}
badgeColor={rest.badgeColor}
/>
)}
<div
className={clsx(
"relative mb-docs_1 rounded-b-docs_DEFAULT",
"w-full max-w-full border",
bgColor,
borderColor,
collapsed && "max-h-[400px] overflow-auto",
!title && "rounded-t-docs_DEFAULT",
(blockStyle === "loud" || colorMode !== "light") &&
"code-block-highlight-dark",
blockStyle === "subtle" &&
colorMode === "light" &&
"code-block-highlight-light",
className
)}
>
<Highlight
theme={
blockStyle === "loud" || colorMode === "dark"
? {
...themes.vsDark,
plain: {
...themes.vsDark.plain,
backgroundColor:
blockStyle === "loud"
? colorMode === "light"
? "#111827"
: "#27282D"
: "#1B1B1F",
},
}
: {
...themes.vsLight,
plain: {
...themes.vsLight.plain,
backgroundColor: "#F9FAFB",
},
}
}
code={source.trim()}
language={lang.toLowerCase()}
{...rest}
>
{({ className: preClassName, style, tokens, ...rest }) => (
<>
<pre
style={{ ...style, fontStretch: "100%" }}
className={clsx(
"relative !my-0 break-words bg-transparent !outline-none",
"overflow-auto break-words rounded-docs_DEFAULT p-0 xs:max-w-[83%]",
preClassName
)}
>
<code
className={clsx(
"text-code-body font-monospace table min-w-full pb-docs_1.5 print:whitespace-pre-wrap",
tokens.length > 1 && "pt-docs_1 pr-docs_1",
tokens.length <= 1 && "!py-docs_0.25 px-[6px]"
)}
>
{tokens.map((line, i) => {
const highlightedLines = transformedHighlights.filter(
(highlight) => highlight.line - 1 === i
)
return (
<CodeBlockLine
line={line}
lineNumber={i}
highlights={highlightedLines}
showLineNumber={!noLineNumbers && tokens.length > 1}
key={i}
bgColorClassName={bgColor}
lineNumberColorClassName={lineNumbersColor}
{...rest}
/>
)
})}
</code>
</pre>
<div
className={clsx(
"absolute hidden md:flex md:justify-end",
"xs:rounded xs:absolute xs:right-0 xs:top-0 xs:w-[calc(10%+24px)] xs:h-full xs:bg-transparent",
tokens.length === 1 && "md:right-[6px] md:top-0",
tokens.length > 1 && "md:right-docs_1 md:top-docs_1"
)}
>
{canShowApiTesting && (
<Tooltip
text="Test API"
tooltipClassName="font-base"
className={clsx(
"h-fit",
tokens.length === 1 && "p-[6px]",
tokens.length > 1 && "px-[6px] pb-[6px]"
)}
>
<PlaySolid
className={clsx("cursor-pointer", iconColor)}
onClick={() => setShowTesting(true)}
/>
</Tooltip>
)}
{!noReport && (
<Tooltip
text="Report Issue"
tooltipClassName="font-base"
className={clsx(
"h-fit",
tokens.length === 1 && "p-[6px]",
tokens.length > 1 && "px-[6px] pb-[6px]"
)}
>
{/* TODO replace with Link once we move away from Docusaurus */}
<LegacyLink
href={`${GITHUB_ISSUES_PREFIX}&title=${encodeURIComponent(
`Docs(Code Issue): `
)}`}
target="_blank"
className={clsx(
blockStyle === "loud" && "hover:bg-medusa-code-bg-base",
"bg-transparent border-none cursor-pointer rounded",
"[&:not(:first-child)]:ml-docs_0.5",
"inline-flex justify-center items-center invisible xs:visible"
)}
rel="noreferrer"
>
<ExclamationCircle className={clsx(iconColor)} />
</LegacyLink>
</Tooltip>
)}
{!noCopy && (
<CopyButton
text={source}
tooltipClassName="font-base"
className={clsx(
"h-fit",
tokens.length === 1 && "p-[6px]",
tokens.length > 1 && "px-[6px] pb-[6px]"
)}
>
<SquareTwoStack className={clsx(iconColor)} />
</CopyButton>
)}
</div>
</>
)}
</Highlight>
</div>
{canShowApiTesting && (
<CSSTransition
unmountOnExit
in={showTesting}
timeout={150}
classNames={{
enter: "animate-fadeIn animate-fastest",
exit: "animate-fadeOut animate-fastest",
}}
>
<ApiRunner
apiMethod={rest.testApiMethod!}
apiUrl={rest.testApiUrl!}
pathData={rest.testPathParams}
bodyData={rest.testBodyParams}
queryData={rest.testQueryParams}
/>
</CSSTransition>
)}
</>
)
}