docs: generate + configure js sdk reference (#9714)
Manually generate the JS SDK reference + add it to the sidebar
This commit is contained in:
@@ -6,7 +6,7 @@ import type { OpenAPIV3 } from "openapi-types"
|
||||
import getSectionId from "@/utils/get-section-id"
|
||||
import { useCallback, useEffect, useMemo, useRef, useState } from "react"
|
||||
import dynamic from "next/dynamic"
|
||||
import { useInView } from "react-intersection-observer"
|
||||
import { InView } from "react-intersection-observer"
|
||||
import {
|
||||
isElmWindow,
|
||||
useIsBrowser,
|
||||
@@ -20,6 +20,7 @@ import { useLoading } from "@/providers/loading"
|
||||
import { useRouter } from "next/navigation"
|
||||
import SectionDivider from "../../Section/Divider"
|
||||
import checkElementInViewport from "../../../utils/check-element-in-viewport"
|
||||
import DividedLoading from "../../DividedLoading"
|
||||
|
||||
const TagOperationCodeSection = dynamic<TagOperationCodeSectionProps>(
|
||||
async () => import("./CodeSection")
|
||||
@@ -46,7 +47,7 @@ const TagOperation = ({
|
||||
() => getSectionId([...(operation.tags || []), operation.operationId]),
|
||||
[operation]
|
||||
)
|
||||
const nodeRef = useRef<Element | null>(null)
|
||||
const nodeRef = useRef(null)
|
||||
const { loading, removeLoading } = useLoading()
|
||||
const { scrollableElement, scrollToTop } = useScrollController()
|
||||
const { isBrowser } = useIsBrowser()
|
||||
@@ -57,40 +58,6 @@ const TagOperation = ({
|
||||
|
||||
return isElmWindow(scrollableElement) ? document.body : scrollableElement
|
||||
}, [isBrowser, scrollableElement])
|
||||
const { ref } = useInView({
|
||||
threshold: 0.3,
|
||||
rootMargin: `112px 0px 112px 0px`,
|
||||
root,
|
||||
onChange: (changedInView) => {
|
||||
if (changedInView) {
|
||||
if (!show) {
|
||||
if (loading) {
|
||||
removeLoading()
|
||||
}
|
||||
setShow(true)
|
||||
}
|
||||
if (location.hash !== path) {
|
||||
router.push(`#${path}`, {
|
||||
scroll: false,
|
||||
})
|
||||
}
|
||||
if (activePath !== path) {
|
||||
setActivePath(path)
|
||||
}
|
||||
}
|
||||
},
|
||||
})
|
||||
|
||||
// Use `useCallback` so we don't recreate the function on each render
|
||||
const setRefs = useCallback(
|
||||
(node: Element | null) => {
|
||||
// Ref's from useRef needs to have the node assigned to `current`
|
||||
nodeRef.current = node
|
||||
// Callback refs, like the one from `useInView`, is a function that takes the node as an argument
|
||||
ref(node)
|
||||
},
|
||||
[ref]
|
||||
)
|
||||
|
||||
const scrollIntoView = useCallback(() => {
|
||||
if (!isBrowser) {
|
||||
@@ -105,14 +72,14 @@ const TagOperation = ({
|
||||
)
|
||||
}
|
||||
setShow(true)
|
||||
}, [scrollToTop, nodeRef, isBrowser])
|
||||
}, [nodeRef, isBrowser, scrollToTop])
|
||||
|
||||
useEffect(() => {
|
||||
if (nodeRef && nodeRef.current) {
|
||||
removeLoading()
|
||||
const currentHash = location.hash.replace("#", "")
|
||||
if (currentHash === path) {
|
||||
setTimeout(scrollIntoView, 100)
|
||||
setTimeout(scrollIntoView, 200)
|
||||
} else if (currentHash.split("_")[0] === path.split("_")[0]) {
|
||||
setShow(true)
|
||||
}
|
||||
@@ -120,36 +87,66 @@ const TagOperation = ({
|
||||
}, [nodeRef, path, scrollIntoView])
|
||||
|
||||
return (
|
||||
<div
|
||||
className={clsx("relative min-h-screen w-full pb-7", className)}
|
||||
<InView
|
||||
id={path}
|
||||
ref={setRefs}
|
||||
threshold={0.3}
|
||||
rootMargin={`112px 0px 112px 0px`}
|
||||
root={root}
|
||||
onChange={(changedInView) => {
|
||||
if (changedInView) {
|
||||
if (!show) {
|
||||
if (loading) {
|
||||
removeLoading()
|
||||
}
|
||||
setShow(true)
|
||||
}
|
||||
if (location.hash !== path) {
|
||||
router.push(`#${path}`, {
|
||||
scroll: false,
|
||||
})
|
||||
}
|
||||
if (activePath !== path) {
|
||||
setActivePath(path)
|
||||
}
|
||||
} else if (
|
||||
nodeRef.current &&
|
||||
!checkElementInViewport(nodeRef.current, 0)
|
||||
) {
|
||||
setShow(false)
|
||||
}
|
||||
}}
|
||||
>
|
||||
<div
|
||||
className={clsx(
|
||||
"flex w-full justify-between gap-1 opacity-0",
|
||||
!show && "invisible",
|
||||
show && "animate-fadeIn"
|
||||
)}
|
||||
style={{
|
||||
animationFillMode: "forwards",
|
||||
}}
|
||||
ref={nodeRef}
|
||||
className={clsx("relative min-h-screen w-full pb-7", className)}
|
||||
>
|
||||
<DividedLayout
|
||||
mainContent={
|
||||
<TagsOperationDescriptionSection operation={operation} />
|
||||
}
|
||||
codeContent={
|
||||
<TagOperationCodeSection
|
||||
method={method || ""}
|
||||
operation={operation}
|
||||
endpointPath={endpointPath}
|
||||
{!show && <DividedLoading className="mt-7" />}
|
||||
{show && (
|
||||
<div
|
||||
className={clsx(
|
||||
"flex w-full justify-between gap-1 opacity-0 animate-fadeIn"
|
||||
)}
|
||||
style={{
|
||||
animationFillMode: "forwards",
|
||||
}}
|
||||
>
|
||||
<DividedLayout
|
||||
mainContent={
|
||||
<TagsOperationDescriptionSection operation={operation} />
|
||||
}
|
||||
codeContent={
|
||||
<TagOperationCodeSection
|
||||
method={method || ""}
|
||||
operation={operation}
|
||||
endpointPath={endpointPath}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
<SectionDivider className="-left-[16px] lg:!-left-1/4" />
|
||||
</div>
|
||||
<SectionDivider className="-left-[16px] lg:!-left-1/4" />
|
||||
</div>
|
||||
</InView>
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
import type { OpenAPIV3 } from "openapi-types"
|
||||
import type { Operation, PathsObject } from "@/types/openapi"
|
||||
import { useSidebar } from "docs-ui"
|
||||
import { Fragment, useEffect } from "react"
|
||||
import { Fragment, Suspense, useEffect } from "react"
|
||||
import dynamic from "next/dynamic"
|
||||
import type { TagOperationProps } from "../Operation"
|
||||
import clsx from "clsx"
|
||||
@@ -48,25 +48,27 @@ const TagPaths = ({ tag, className, paths }: TagPathsProps) => {
|
||||
}, [paths])
|
||||
|
||||
return (
|
||||
<div className={clsx("relative", className)}>
|
||||
{loading && <DividedLoading className="mt-7" />}
|
||||
{Object.entries(paths).map(([endpointPath, operations], pathIndex) => (
|
||||
<Fragment key={pathIndex}>
|
||||
{Object.entries(operations).map(
|
||||
([method, operation], operationIndex) => (
|
||||
<TagOperation
|
||||
method={method}
|
||||
operation={operation as Operation}
|
||||
tag={tag}
|
||||
key={`${pathIndex}-${operationIndex}`}
|
||||
endpointPath={endpointPath}
|
||||
className={clsx("pt-7")}
|
||||
/>
|
||||
)
|
||||
)}
|
||||
</Fragment>
|
||||
))}
|
||||
</div>
|
||||
<Suspense>
|
||||
<div className={clsx("relative", className)}>
|
||||
{loading && <DividedLoading className="mt-7" />}
|
||||
{Object.entries(paths).map(([endpointPath, operations], pathIndex) => (
|
||||
<Fragment key={pathIndex}>
|
||||
{Object.entries(operations).map(
|
||||
([method, operation], operationIndex) => (
|
||||
<TagOperation
|
||||
method={method}
|
||||
operation={operation as Operation}
|
||||
tag={tag}
|
||||
key={`${pathIndex}-${operationIndex}`}
|
||||
endpointPath={endpointPath}
|
||||
className={clsx("pt-7")}
|
||||
/>
|
||||
)
|
||||
)}
|
||||
</Fragment>
|
||||
))}
|
||||
</div>
|
||||
</Suspense>
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
"use client"
|
||||
|
||||
import { useEffect, useMemo, useRef } from "react"
|
||||
import { Suspense, useEffect, useMemo, useRef } from "react"
|
||||
import { SchemaObject } from "../../../../types/openapi"
|
||||
import TagOperationParameters from "../../Operation/Parameters"
|
||||
import {
|
||||
@@ -114,41 +114,43 @@ const TagSectionSchema = ({ schema, tagName }: TagSectionSchemaProps) => {
|
||||
}
|
||||
|
||||
return (
|
||||
<InView
|
||||
as="div"
|
||||
id={schemaSlug}
|
||||
initialInView={true}
|
||||
onChange={handleViewChange}
|
||||
root={root}
|
||||
threshold={0.1}
|
||||
>
|
||||
<DividedLayout
|
||||
mainContent={
|
||||
<SectionContainer ref={paramsRef}>
|
||||
<h2>{formattedName} Object</h2>
|
||||
<h4 className="border-medusa-border-base border-b py-1.5 mt-2">
|
||||
Fields
|
||||
</h4>
|
||||
<TagOperationParameters schemaObject={schema} topLevel={true} />
|
||||
</SectionContainer>
|
||||
}
|
||||
codeContent={
|
||||
<SectionContainer noDivider>
|
||||
{examples.length && (
|
||||
<CodeBlock
|
||||
source={examples[0].content}
|
||||
lang="json"
|
||||
title={`The ${formattedName} Object`}
|
||||
className={clsx("overflow-auto")}
|
||||
style={{
|
||||
maxHeight: "100vh",
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
</SectionContainer>
|
||||
}
|
||||
/>
|
||||
</InView>
|
||||
<Suspense>
|
||||
<InView
|
||||
as="div"
|
||||
id={schemaSlug}
|
||||
initialInView={true}
|
||||
onChange={handleViewChange}
|
||||
root={root}
|
||||
threshold={0.1}
|
||||
>
|
||||
<DividedLayout
|
||||
mainContent={
|
||||
<SectionContainer ref={paramsRef}>
|
||||
<h2>{formattedName} Object</h2>
|
||||
<h4 className="border-medusa-border-base border-b py-1.5 mt-2">
|
||||
Fields
|
||||
</h4>
|
||||
<TagOperationParameters schemaObject={schema} topLevel={true} />
|
||||
</SectionContainer>
|
||||
}
|
||||
codeContent={
|
||||
<SectionContainer noDivider>
|
||||
{examples.length && (
|
||||
<CodeBlock
|
||||
source={examples[0].content}
|
||||
lang="json"
|
||||
title={`The ${formattedName} Object`}
|
||||
className={clsx("overflow-auto")}
|
||||
style={{
|
||||
maxHeight: "100vh",
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
</SectionContainer>
|
||||
}
|
||||
/>
|
||||
</InView>
|
||||
</Suspense>
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
"use client"
|
||||
|
||||
import getSectionId from "@/utils/get-section-id"
|
||||
import { useInView } from "react-intersection-observer"
|
||||
import { InView } from "react-intersection-observer"
|
||||
import { useEffect, useMemo, useState } from "react"
|
||||
import {
|
||||
isElmWindow,
|
||||
@@ -65,30 +65,6 @@ const TagSectionComponent = ({ tag }: TagSectionProps) => {
|
||||
|
||||
return isElmWindow(scrollableElement) ? document.body : scrollableElement
|
||||
}, [scrollableElement, isBrowser])
|
||||
const { ref, inView } = useInView({
|
||||
threshold: 0.8,
|
||||
rootMargin: `112px 0px 112px 0px`,
|
||||
root,
|
||||
onChange: (inView) => {
|
||||
if (inView && !loadData) {
|
||||
setLoadData(true)
|
||||
}
|
||||
if (inView) {
|
||||
// ensure that the hash link doesn't change if it links to an inner path
|
||||
const currentHashArr = location.hash.replace("#", "").split("_")
|
||||
if (currentHashArr.length < 2 || currentHashArr[0] !== slugTagName) {
|
||||
if (location.hash !== slugTagName) {
|
||||
router.push(`#${slugTagName}`, {
|
||||
scroll: false,
|
||||
})
|
||||
}
|
||||
if (activePath !== slugTagName) {
|
||||
setActivePath(slugTagName)
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
})
|
||||
const { data: schemaData } = useSWR<{
|
||||
schema: SchemaObject
|
||||
}>(
|
||||
@@ -136,10 +112,31 @@ const TagSectionComponent = ({ tag }: TagSectionProps) => {
|
||||
}, [slugTagName, activePath, isBrowser])
|
||||
|
||||
return (
|
||||
<div
|
||||
<InView
|
||||
className={clsx("min-h-screen", !loadData && "relative")}
|
||||
id={slugTagName}
|
||||
ref={ref}
|
||||
threshold={0.8}
|
||||
rootMargin={`112px 0px 112px 0px`}
|
||||
root={root}
|
||||
onChange={(inView) => {
|
||||
if (inView) {
|
||||
if (!loadData) {
|
||||
setLoadData(true)
|
||||
}
|
||||
// ensure that the hash link doesn't change if it links to an inner path
|
||||
const currentHashArr = location.hash.replace("#", "").split("_")
|
||||
if (currentHashArr.length < 2 || currentHashArr[0] !== slugTagName) {
|
||||
if (location.hash !== slugTagName) {
|
||||
router.push(`#${slugTagName}`, {
|
||||
scroll: false,
|
||||
})
|
||||
}
|
||||
if (activePath !== slugTagName) {
|
||||
setActivePath(slugTagName)
|
||||
}
|
||||
}
|
||||
}
|
||||
}}
|
||||
>
|
||||
<DividedLayout
|
||||
mainContent={
|
||||
@@ -188,7 +185,7 @@ const TagSectionComponent = ({ tag }: TagSectionProps) => {
|
||||
</LoadingProvider>
|
||||
)}
|
||||
{!loadData && <SectionDivider className="lg:!-left-1" />}
|
||||
</div>
|
||||
</InView>
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { OpenAPIV3 } from "openapi-types"
|
||||
import { TagSectionProps } from "./Section"
|
||||
import dynamic from "next/dynamic"
|
||||
import { Suspense } from "react"
|
||||
|
||||
const TagSection = dynamic<TagSectionProps>(
|
||||
async () => import("./Section")
|
||||
@@ -12,11 +13,11 @@ type TagsProps = {
|
||||
|
||||
const Tags = ({ tags }: TagsProps) => {
|
||||
return (
|
||||
<>
|
||||
<Suspense>
|
||||
{tags?.map((tag) => (
|
||||
<TagSection tag={tag} key={tag.name} />
|
||||
))}
|
||||
</>
|
||||
</Suspense>
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user