From 8ceb895d9c36f753c724cf98a71fddd3789a5280 Mon Sep 17 00:00:00 2001 From: Shahed Nasser Date: Tue, 5 Apr 2022 12:22:25 +0300 Subject: [PATCH] docs: improve performance of API reference (#1247) --- docs/api/store-spec3.json | 2 +- www/reference/gatsby-node.js | 4 +- www/reference/src/components/content/index.js | 15 ++--- .../src/components/content/method.js | 4 +- .../src/components/content/section.js | 36 ++++++---- www/reference/src/components/layout.js | 28 ++++++-- .../src/components/search/hit-component.js | 11 ++- www/reference/src/components/search/index.js | 16 +++-- .../src/components/side-bar/index.js | 11 +-- .../src/components/side-bar/sidebar-item.js | 26 ++++--- www/reference/src/components/topbar.js | 15 +++-- .../src/context/navigation-context.js | 67 ++++++++++++------- www/reference/src/templates/reference-page.js | 19 ++++-- 13 files changed, 160 insertions(+), 94 deletions(-) diff --git a/docs/api/store-spec3.json b/docs/api/store-spec3.json index b72d490f15..1e8028adf1 100644 --- a/docs/api/store-spec3.json +++ b/docs/api/store-spec3.json @@ -1512,7 +1512,7 @@ "/store/carts/{id}": { "post": { "operationId": "PostCartsCartPaymentMethodUpdate", - "summary": "Update a Cart\"", + "summary": "Update a Cart", "description": "Updates a Cart.", "parameters": [ { diff --git a/www/reference/gatsby-node.js b/www/reference/gatsby-node.js index c3fe7c8ce0..403d5bb90e 100644 --- a/www/reference/gatsby-node.js +++ b/www/reference/gatsby-node.js @@ -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 }, }, }) }) diff --git a/www/reference/src/components/content/index.js b/www/reference/src/components/content/index.js index 189fb04225..cdd10911d7 100644 --- a/www/reference/src/components/content/index.js +++ b/www/reference/src/components/content/index.js @@ -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 ( { }, }} > -
- {data.sections.map((s, i) => { - return
- })} -
+
) diff --git a/www/reference/src/components/content/method.js b/www/reference/src/components/content/method.js index 773844dee7..4528b0f273 100644 --- a/www/reference/src/components/content/method.js +++ b/www/reference/src/components/content/method.js @@ -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]) diff --git a/www/reference/src/components/content/section.js b/www/reference/src/components/content/section.js index 3b9386c3cf..5ede7e692b 100644 --- a/www/reference/src/components/content/section.js +++ b/www/reference/src/components/content/section.js @@ -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} /> ) diff --git a/www/reference/src/components/layout.js b/www/reference/src/components/layout.js index 13287c60d3..2088349453 100644 --- a/www/reference/src/components/layout.js +++ b/www/reference/src/components/layout.js @@ -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 ( - + { }} > - {children} + {children} - + ) } diff --git a/www/reference/src/components/search/hit-component.js b/www/reference/src/components/search/hit-component.js index 1612fe757c..1075c2a34a 100644 --- a/www/reference/src/components/search/hit-component.js +++ b/www/reference/src/components/search/hit-component.js @@ -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 }) } } diff --git a/www/reference/src/components/search/index.js b/www/reference/src/components/search/index.js index 2c7ff5560d..186b6f6cb3 100644 --- a/www/reference/src/components/search/index.js +++ b/www/reference/src/components/search/index.js @@ -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 = () => { } navigator={{ navigate({ item }) { if (item.url.includes(`api/${api}`)) { diff --git a/www/reference/src/components/side-bar/index.js b/www/reference/src/components/side-bar/index.js index a49f1ec487..24f332736c 100644 --- a/www/reference/src/components/side-bar/index.js +++ b/www/reference/src/components/side-bar/index.js @@ -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; } diff --git a/www/reference/src/components/side-bar/sidebar-item.js b/www/reference/src/components/side-bar/sidebar-item.js index 21d32e96ec..4726c354da 100644 --- a/www/reference/src/components/side-bar/sidebar-item.js +++ b/www/reference/src/components/side-bar/sidebar-item.js @@ -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 ( { {section.section_name} } - open={ - currentSection === convertToKebabCase(section.section_name) || - openSections.includes(convertToKebabCase(section.section_name)) - } + open={isOpen} onTriggerOpening={handleClick} transitionTime={1} > diff --git a/www/reference/src/components/topbar.js b/www/reference/src/components/topbar.js index 3431cd64c6..f533cbeadb 100644 --- a/www/reference/src/components/topbar.js +++ b/www/reference/src/components/topbar.js @@ -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 }) => { > - + ) diff --git a/www/reference/src/context/navigation-context.js b/www/reference/src/context/navigation-context.js index 93a8c3e404..bd14c09c31 100644 --- a/www/reference/src/context/navigation-context.js +++ b/www/reference/src/context/navigation-context.js @@ -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) } diff --git a/www/reference/src/templates/reference-page.js b/www/reference/src/templates/reference-page.js index 9fe647c603..4b93cb1eb6 100644 --- a/www/reference/src/templates/reference-page.js +++ b/www/reference/src/templates/reference-page.js @@ -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 ( - {`API | Medusa Commerce API Reference`} + {`API | Medusa API Reference`} - + ) }