docs: improve performance of API reference (#1247)

This commit is contained in:
Shahed Nasser
2022-04-05 12:22:25 +03:00
committed by GitHub
parent cab5821f55
commit 8ceb895d9c
13 changed files with 160 additions and 94 deletions

View File

@@ -1512,7 +1512,7 @@
"/store/carts/{id}": {
"post": {
"operationId": "PostCartsCartPaymentMethodUpdate",
"summary": "Update a Cart\"",
"summary": "Update a Cart",
"description": "Updates a Cart.",
"parameters": [
{

View File

@@ -331,7 +331,7 @@ const createAllPages = (sections, api, siteData, createPage, template) => {
api: api,
title: edge.section.section_name,
description: edge.section.schema ? edge.section.schema.description : "",
to: { section: baseURL, method: null },
to: { section: baseURL, method: null, sectionObj: edge.section },
},
})
edge.section.paths.forEach(p => {
@@ -345,7 +345,7 @@ const createAllPages = (sections, api, siteData, createPage, template) => {
api: api,
title: method.summary,
description: method.description || "",
to: { section: baseURL, method: methodURL },
to: { section: baseURL, method: methodURL, sectionObj: edge.section },
},
})
})

View File

@@ -1,9 +1,10 @@
import React from "react"
import { Box, Flex } from "theme-ui"
import Topbar from "../topbar"
import Section from "./section"
const Content = ({ data, api }) => {
import React from "react"
import Section from "./section"
import Topbar from "../topbar"
const Content = ({ data, currentSection, api }) => {
return (
<Flex
sx={{
@@ -20,11 +21,7 @@ const Content = ({ data, api }) => {
},
}}
>
<main className="DocSearch-content">
{data.sections.map((s, i) => {
return <Section key={i} data={s} api={api} />
})}
</main>
<Section data={currentSection} api={api} />
</Box>
</Flex>
)

View File

@@ -13,7 +13,7 @@ import { formatMethodParams } from "../../utils/format-parameters"
import { formatRoute } from "../../utils/format-route"
import useInView from "../../hooks/use-in-view"
const Method = ({ data, section, pathname, api }) => {
const Method = ({ data, section, sectionData, pathname, api }) => {
const { parameters, requestBody, description, method, summary } = data
const jsonResponse = data.responses[0].content?.[0].json
const { updateHash, updateMetadata } = useContext(NavigationContext)
@@ -27,7 +27,7 @@ const Method = ({ data, section, pathname, api }) => {
useEffect(() => {
if (isInView) {
updateHash(section, convertToKebabCase(summary))
updateHash(section, convertToKebabCase(summary), sectionData)
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [isInView])

View File

@@ -1,21 +1,22 @@
import React, { useState, useRef, useEffect, useContext } from "react"
import { Flex, Box, Heading, Text, Button } from "theme-ui"
import Method from "./method"
import Parameters from "./parameters"
import { convertToKebabCase } from "../../utils/convert-to-kebab-case"
import EndpointContainer from "./endpoint-container"
import Markdown from "react-markdown"
import JsonContainer from "./json-container"
import ResponsiveContainer from "./responsive-container"
import Description from "./description"
import NavigationContext from "../../context/navigation-context"
import { Box, Button, Flex, Heading, Text } from "theme-ui"
import React, { useContext, useEffect, useRef, useState } from "react"
import ChevronDown from "../icons/chevron-down"
import Description from "./description"
import EndpointContainer from "./endpoint-container"
import JsonContainer from "./json-container"
import Markdown from "react-markdown"
import Method from "./method"
import NavigationContext from "../../context/navigation-context"
import Parameters from "./parameters"
import ResponsiveContainer from "./responsive-container"
import { convertToKebabCase } from "../../utils/convert-to-kebab-case"
import useInView from "../../hooks/use-in-view"
const Section = ({ data, api }) => {
const { section } = data
const section = data;
const [isExpanded, setIsExpanded] = useState(false)
const { openSections, updateSection, updateMetadata } = useContext(
const { openSections, updateSection, updateMetadata, updateHash } = useContext(
NavigationContext
)
@@ -61,6 +62,12 @@ const Section = ({ data, api }) => {
}
}, [section.section_name, openSections, openSections.length])
useEffect(() => {
if (section.section_name) {
updateHash(convertToKebabCase(section.section_name), section.paths && section.paths.length ? (section.paths[0].methods[0].path || '') : '', section)
}
}, [section.section_name])
const [containerRef, isInView] = useInView({
root: null,
rootMargin: "0px 0px -80% 0px",
@@ -70,7 +77,7 @@ const Section = ({ data, api }) => {
useEffect(() => {
const handleInView = () => {
if (isInView) {
updateSection(convertToKebabCase(section.section_name))
updateSection({id: convertToKebabCase(section.section_name), section})
}
}
handleInView()
@@ -188,6 +195,7 @@ const Section = ({ data, api }) => {
key={i}
data={m}
section={convertToKebabCase(section.section_name)}
sectionData={section}
pathname={p.name}
/>
)

View File

@@ -1,10 +1,30 @@
import { Box, Flex } from "theme-ui"
import React from "react"
import { Flex, Box } from "theme-ui"
import Sidebar from "./side-bar"
import styled from "@emotion/styled"
const LayoutContainer = styled(Flex)`
--side-bar-width: 220px;
@media screen and (min-width: 1680px) {
--side-bar-width: 280px;
}
`
const ContentBox = styled(Box)`
@media screen and (min-width: 849px) {
width: calc(100% - var(--side-bar-width));
}
@media screen and (max-width: 848px) {
width: 100%;
}
`
const Layout = ({ data, api, children }) => {
return (
<Flex sx={{ p: "0", m: "0", overflow: "hidden" }}>
<LayoutContainer sx={{ p: "0", m: "0", overflow: "hidden" }}>
<Flex
sx={{
position: "absolute",
@@ -17,9 +37,9 @@ const Layout = ({ data, api, children }) => {
}}
>
<Sidebar data={data} api={api} />
<Box>{children}</Box>
<ContentBox>{children}</ContentBox>
</Flex>
</Flex>
</LayoutContainer>
)
}

View File

@@ -1,9 +1,10 @@
import React, { useContext } from "react"
import { convertToKebabCase } from "../../utils/convert-to-kebab-case"
import NavigationContext from "../../context/navigation-context"
import { convertToKebabCase } from "../../utils/convert-to-kebab-case"
import { navigate } from "gatsby"
const HitComponent = ({ hit, children }) => {
const HitComponent = ({ hit, children, data }) => {
const { goTo, api } = useContext(NavigationContext)
let { url, type, hierarchy } = hit
@@ -20,13 +21,17 @@ const HitComponent = ({ hit, children }) => {
*/
const goToHierarchy = e => {
e.preventDefault()
//find section
let section = data.sections.find((s) => s.section.section_name == hierarchy.lvl1);
section = section ? section.section : {}
if (hierarchy.lvl2) {
goTo({
section: convertToKebabCase(hierarchy.lvl1),
method: convertToKebabCase(hierarchy.lvl2),
sectionObj: section
})
} else {
goTo({ section: convertToKebabCase(hierarchy.lvl1) })
goTo({ section: convertToKebabCase(hierarchy.lvl1), sectionObj: section })
}
}

View File

@@ -1,6 +1,8 @@
import React, { useContext } from "react"
import { DocSearch } from "@docsearch/react"
import "../../medusa-plugin-themes/docsearch/theme.css"
import React, { useContext } from "react"
import { DocSearch } from "@docsearch/react"
import HitComponent from "./hit-component"
import NavigationContext from "../../context/navigation-context"
import { convertToKebabCase } from "../../utils/convert-to-kebab-case"
@@ -8,7 +10,7 @@ import { navigate } from "gatsby-link"
const algoliaApiKey = process.env.ALGOLIA_API_KEY || "temp"
const Search = () => {
const Search = ({data}) => {
const { goTo, api } = useContext(NavigationContext)
const getOtherAPI = () => {
@@ -36,13 +38,17 @@ const Search = () => {
*/
const goToHierarchy = item => {
const { hierarchy } = item
//find section
let section = data.sections.find((s) => s.section.section_name == hierarchy.lvl1);
section = section ? section.section : {}
if (hierarchy.lvl2) {
goTo({
section: convertToKebabCase(hierarchy.lvl1),
method: convertToKebabCase(hierarchy.lvl2),
sectionObj: section
})
} else {
goTo({ section: convertToKebabCase(hierarchy.lvl1) })
goTo({ section: convertToKebabCase(hierarchy.lvl1), sectionObj: section })
}
}
@@ -67,7 +73,7 @@ const Search = () => {
<DocSearch
apiKey={algoliaApiKey}
indexName="medusa-commerce"
hitComponent={HitComponent}
hitComponent={({hit, children}) => <HitComponent data={data} hit={hit} children={children} />}
navigator={{
navigate({ item }) {
if (item.url.includes(`api/${api}`)) {

View File

@@ -1,19 +1,14 @@
import { Box, Flex, Image } from "theme-ui"
import React, { useEffect, useState } from "react"
import { Flex, Image, Box } from "theme-ui"
import styled from "@emotion/styled"
import Logo from "../../assets/logo.svg"
import LogoMuted from "../../assets/logo-muted.svg"
import SideBarItem from "./sidebar-item"
import SideBarSelector from "./sidebar-selector"
import { navigate } from "gatsby"
import styled from "@emotion/styled"
const SideBarContainer = styled(Flex)`
--side-bar-width: 220px;
@media screen and (min-width: 1680px) {
--side-bar-width: 280px;
}
@media screen and (max-width: 848px) {
display: none;
}

View File

@@ -1,10 +1,11 @@
import React, { useContext } from "react"
import Collapsible from "react-collapsible"
import { Flex, Box, Text } from "theme-ui"
import styled from "@emotion/styled"
import { convertToKebabCase } from "../../utils/convert-to-kebab-case"
import { Box, Flex, Text } from "theme-ui"
import React, { useContext, useEffect, useState } from "react"
import ChevronDown from "../icons/chevron-down"
import Collapsible from "react-collapsible"
import NavigationContext from "../../context/navigation-context"
import { convertToKebabCase } from "../../utils/convert-to-kebab-case"
import styled from "@emotion/styled"
const StyledCollapsible = styled(Collapsible)`
margin-bottom: 10px;
@@ -26,6 +27,7 @@ const SideBarItem = ({ item }) => {
currentSection,
goTo,
} = useContext(NavigationContext)
const [isOpen, setIsOpen] = useState(false);
const { section } = item
const subItems = section.paths
.map(p => {
@@ -47,16 +49,21 @@ const SideBarItem = ({ item }) => {
if (element) {
element.scrollIntoView()
if (!openSections.includes(id)) {
openSection(id)
openSection({id, section})
}
}
}
const handleSubClick = path => {
const id = convertToKebabCase(section.section_name)
goTo({ section: id, method: path })
goTo({ section: id, method: path, sectionObj: section })
}
useEffect(() => {
setIsOpen(currentSection === convertToKebabCase(section.section_name) ||
openSections.includes(convertToKebabCase(section.section_name)));
}, [section.section_name, currentSection, openSections])
return (
<Container id={`nav-${convertToKebabCase(section.section_name)}`}>
<StyledCollapsible
@@ -86,10 +93,7 @@ const SideBarItem = ({ item }) => {
{section.section_name} <ChevronDown />
</Flex>
}
open={
currentSection === convertToKebabCase(section.section_name) ||
openSections.includes(convertToKebabCase(section.section_name))
}
open={isOpen}
onTriggerOpening={handleClick}
transitionTime={1}
>

View File

@@ -1,12 +1,12 @@
import { Box, Flex, Link, Select } from "@theme-ui/components"
import { navigate } from "gatsby-link"
import React, { useContext } from "react"
import ChevronDown from "./icons/chevron-down"
import GitHub from "../components/icons/github"
import NavigationContext from "../context/navigation-context"
import { convertToKebabCase } from "../utils/convert-to-kebab-case"
import ChevronDown from "./icons/chevron-down"
import Search from "./search"
import { convertToKebabCase } from "../utils/convert-to-kebab-case"
import { navigate } from "gatsby-link"
const Topbar = ({ data, api }) => {
const { goTo, reset, currentSection } = useContext(NavigationContext)
@@ -15,7 +15,10 @@ const Topbar = ({ data, api }) => {
const parts = e.target.value.split(" ")
if (parts[0] === api) {
goTo({ section: parts[1] })
//find section
let sectionObj = data.sections.find((s) => convertToKebabCase(s.section.section_name) === parts[1]);
sectionObj = sectionObj ? sectionObj.section : {};
goTo({ section: parts[1], sectionObj })
} else {
reset()
navigate(`/api/${api === "admin" ? "store" : "admin"}`)
@@ -112,7 +115,7 @@ const Topbar = ({ data, api }) => {
>
<GitHub />
</Link>
<Search />
<Search data={data} />
</Flex>
</Flex>
)

View File

@@ -1,4 +1,5 @@
import React, { useReducer } from "react"
import { checkDisplay } from "../utils/check-display"
import scrollParent from "../utils/scroll-parent"
import types from "./types"
@@ -7,6 +8,11 @@ export const defaultNavigationContext = {
api: "null",
setApi: () => {},
currentSection: null,
currentSectionObj: {
section_name: "",
paths: [],
schema: {}
},
updateSection: () => {},
currentHash: null,
updateHash: () => {},
@@ -21,6 +27,7 @@ const NavigationContext = React.createContext(defaultNavigationContext)
export default NavigationContext
const reducer = (state, action) => {
let obj = []
switch (action.type) {
case types.SET_API: {
return {
@@ -29,23 +36,30 @@ const reducer = (state, action) => {
}
}
case types.UPDATE_HASH:
return {
...state,
currentSection: action.payload.section,
currentHash: action.payload.method,
}
case types.UPDATE_SECTION:
return {
...state,
currentSection: action.payload,
currentHash: null,
}
case types.OPEN_SECTION:
const obj = state.openSections
obj.push(action.payload)
obj.push(action.payload.section)
return {
...state,
openSections: obj,
currentSection: action.payload.section,
currentHash: action.payload.method,
currentSectionObj: action.payload.sectionObj
}
case types.UPDATE_SECTION:
obj.push(action.payload.id)
return {
...state,
openSections: obj,
currentSection: action.payload.id,
currentHash: null,
currentSectionObj: action.payload.section
}
case types.OPEN_SECTION:
obj.push(action.payload.id)
return {
...state,
openSections: obj,
currentSection: action.payload.id,
currentSectionObj: action.payload.section
}
case types.RESET:
return {
@@ -53,6 +67,11 @@ const reducer = (state, action) => {
openSections: [],
currentSection: null,
currentHash: null,
currentSectionObj: {
section_name: "",
paths: [],
schema: {}
}
}
case types.UPDATE_METADATA:
return {
@@ -108,10 +127,10 @@ export const NavigationProvider = ({ children }) => {
dispatch({ type: types.UPDATE_METADATA, payload: metadata })
}
const updateHash = (section, method) => {
const updateHash = (section, method, sectionObj) => {
dispatch({
type: types.UPDATE_HASH,
payload: { method: method, section: section },
payload: { method: method, section: section, sectionObj },
})
window.history.replaceState(
null,
@@ -121,21 +140,21 @@ export const NavigationProvider = ({ children }) => {
scrollNav(method)
}
const updateSection = section => {
dispatch({ type: types.UPDATE_SECTION, payload: section })
window.history.replaceState(null, "", `/api/${state.api}/${section}`)
scrollNav(section)
const updateSection = ({id, section}) => {
dispatch({ type: types.UPDATE_SECTION, payload: {id, section} })
window.history.replaceState(null, "", `/api/${state.api}/${id}`)
scrollNav(id)
}
const openSection = sectionName => {
dispatch({ type: types.OPEN_SECTION, payload: sectionName })
const openSection = ({id, section}) => {
dispatch({ type: types.OPEN_SECTION, payload: {id, section} })
}
const goTo = to => {
const { section, method } = to
const { section, method, sectionObj } = to
if (!state.openSections.includes(section)) {
openSection(section)
openSection({id: section, section: sectionObj})
}
scrollToElement(method || section)
}

View File

@@ -1,14 +1,15 @@
import React, { useContext, useEffect, useState } from "react"
import { Helmet } from "react-helmet"
import Layout from "../components/layout"
import Content from "../components/content"
import { Helmet } from "react-helmet"
import Layout from "../components/layout"
import NavigationContext from "../context/navigation-context"
import { convertToKebabCase } from "../utils/convert-to-kebab-case"
export default function ReferencePage({
pageContext: { data, api, title, description, to },
}) {
const { setApi, goTo, metadata } = useContext(NavigationContext)
const { setApi, goTo, metadata, currentSection, currentSectionObj } = useContext(NavigationContext)
const [siteData, setSiteData] = useState({
title: title,
description: description,
@@ -18,6 +19,14 @@ export default function ReferencePage({
setApi(api)
if (to) {
goTo(to)
} else if (data.sections && data.sections.length) {
//go to the first section
const firstSection = data.sections[0].section;
goTo({
section: convertToKebabCase(firstSection.section_name),
method: firstSection.paths && firstSection.paths.length ? firstSection.paths[0].methods[0].method : '',
sectionObj: firstSection
})
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [])
@@ -34,10 +43,10 @@ export default function ReferencePage({
return (
<Layout data={data} api={api}>
<Helmet>
<title>{`API | Medusa Commerce API Reference`}</title>
<title>{`API | Medusa API Reference`}</title>
<meta name="description" content={siteData.description} />
</Helmet>
<Content data={data} api={api} />
<Content data={data} currentSection={currentSectionObj} api={api} />
</Layout>
)
}