feat: Update to API references look and feel (#343)
Co-authored-by: Vadim Smirnov <smirnou.vadzim@gmail.com> Co-authored-by: zakariasaad <zakaria.elas@gmail.com> Co-authored-by: Vilfred Sikker <vilfredsikker@gmail.com> Co-authored-by: olivermrbl <oliver@mrbltech.com>
This commit is contained in:
committed by
GitHub
parent
40400b483c
commit
143f06aa39
@@ -0,0 +1,54 @@
|
||||
import React from "react"
|
||||
import { Flex, Box, Text } from "theme-ui"
|
||||
|
||||
const CodeBox = ({ header, children }) => {
|
||||
return (
|
||||
<Box
|
||||
sx={{
|
||||
background: "fadedContrast",
|
||||
borderRadius: "small",
|
||||
boxShadow: "0 0 0 1px rgb(0 0 0 / 7%)",
|
||||
alignSelf: "flex-start",
|
||||
marginLeft: "auto",
|
||||
marginRight: "auto",
|
||||
width: "100%",
|
||||
mb: "4",
|
||||
}}
|
||||
>
|
||||
<Box
|
||||
sx={{
|
||||
bg: "faded",
|
||||
p: "8px 10px",
|
||||
letterSpacing: "0.01em",
|
||||
borderRadius: "8px 8px 0 0",
|
||||
}}
|
||||
>
|
||||
<Text variant="small" sx={{ fontWeight: "400" }}>
|
||||
{header}
|
||||
</Text>
|
||||
</Box>
|
||||
<Box
|
||||
sx={{
|
||||
position: "relative",
|
||||
boxSizing: "content-box",
|
||||
maxHeight: "calc(90vh - 20px)",
|
||||
minHeight: "10px",
|
||||
}}
|
||||
>
|
||||
<Flex
|
||||
sx={{
|
||||
flexDirection: "column",
|
||||
position: "relative",
|
||||
minHeight: "inherit",
|
||||
maxHeight: "inherit",
|
||||
overflowY: "auto",
|
||||
}}
|
||||
>
|
||||
{children}
|
||||
</Flex>
|
||||
</Box>
|
||||
</Box>
|
||||
)
|
||||
}
|
||||
|
||||
export default CodeBox
|
||||
@@ -0,0 +1,130 @@
|
||||
import React, { useState } from "react"
|
||||
import Collapsible from "react-collapsible"
|
||||
import { Flex, Box, Text, Heading } from "theme-ui"
|
||||
import Markdown from "react-markdown"
|
||||
import Description from "./description"
|
||||
|
||||
const NestedCollapsible = ({ properties, title }) => {
|
||||
const [isOpen, setIsOpen] = useState(false)
|
||||
return (
|
||||
<Box
|
||||
mt={2}
|
||||
sx={{
|
||||
"& .child-attrs": {
|
||||
cursor: "pointer",
|
||||
fontSize: "12px",
|
||||
p: "6px 10px",
|
||||
boxSizing: "border-box",
|
||||
width: "max-content",
|
||||
borderRadius: "small",
|
||||
border: "1px solid",
|
||||
borderColor: "faded",
|
||||
},
|
||||
|
||||
"& .child-attrs.is-open": {
|
||||
width: "100%",
|
||||
borderBottom: "none",
|
||||
borderBottomLeftRadius: "0",
|
||||
borderBottomRightRadius: "0",
|
||||
},
|
||||
}}
|
||||
>
|
||||
<Collapsible
|
||||
transitionTime={50}
|
||||
triggerClassName={"child-attrs"}
|
||||
triggerOpenedClassName={"child-attrs"}
|
||||
triggerTagName="div"
|
||||
trigger={
|
||||
<Flex
|
||||
sx={{
|
||||
alignItems: "baseline",
|
||||
fontSize: "13px",
|
||||
fontWeight: "400",
|
||||
}}
|
||||
>
|
||||
<Box
|
||||
mr={1}
|
||||
className={isOpen ? "rotated" : null}
|
||||
sx={{
|
||||
userSelect: "none",
|
||||
transition: "all 0.2s ease",
|
||||
transform: "rotate(45deg)",
|
||||
"&.rotated": {
|
||||
transform: "rotate(0deg)",
|
||||
},
|
||||
}}
|
||||
>
|
||||
×
|
||||
</Box>{" "}
|
||||
<Text
|
||||
sx={{ fontSize: "0", fontFamily: "body", userSelect: "none" }}
|
||||
>{`${isOpen ? "Hide" : "Show"} child attributes`}</Text>
|
||||
</Flex>
|
||||
}
|
||||
onTriggerOpening={() => setIsOpen(true)}
|
||||
onTriggerClosing={() => setIsOpen(false)}
|
||||
>
|
||||
<Box
|
||||
sx={{
|
||||
padding: "2",
|
||||
borderRadius: "small",
|
||||
borderTopLeftRadius: 0,
|
||||
borderTopRightRadius: 0,
|
||||
border: "hairline",
|
||||
borderColor: "faded",
|
||||
}}
|
||||
mb="2"
|
||||
>
|
||||
<Heading as="h3" p={2} sx={{ fontFamily: "body", fontWeight: "500" }}>
|
||||
{title}
|
||||
</Heading>
|
||||
{properties.map((param, i) => {
|
||||
return (
|
||||
<Box
|
||||
p={2}
|
||||
sx={{
|
||||
borderTop: "hairline",
|
||||
}}
|
||||
key={i}
|
||||
>
|
||||
<Flex
|
||||
sx={{
|
||||
fontSize: "0",
|
||||
alignItems: "baseline",
|
||||
pb: "1",
|
||||
fontFamily: "monospace",
|
||||
}}
|
||||
>
|
||||
<Box mr={2} fontSize={"12px"}>
|
||||
{param.property}
|
||||
</Box>
|
||||
<Text color={"gray"} fontSize={"10px"}>
|
||||
{param.type}
|
||||
</Text>
|
||||
{param.required && (
|
||||
<Text ml={1} fontSize={"10px"} variant="labels.required">
|
||||
required
|
||||
</Text>
|
||||
)}
|
||||
</Flex>
|
||||
<Description>
|
||||
<Text
|
||||
sx={{
|
||||
fontSize: "0",
|
||||
lineHeight: "26px",
|
||||
fontFamily: "body",
|
||||
}}
|
||||
>
|
||||
<Markdown>{param.description}</Markdown>
|
||||
</Text>
|
||||
</Description>
|
||||
</Box>
|
||||
)
|
||||
})}
|
||||
</Box>
|
||||
</Collapsible>
|
||||
</Box>
|
||||
)
|
||||
}
|
||||
|
||||
export default NestedCollapsible
|
||||
@@ -0,0 +1,20 @@
|
||||
import React from "react"
|
||||
import { Box } from "theme-ui"
|
||||
|
||||
const Description = ({ children }) => {
|
||||
return (
|
||||
<Box
|
||||
sx={{
|
||||
code: {
|
||||
backgroundColor: "faded",
|
||||
borderRadius: "4px",
|
||||
p: "3px",
|
||||
},
|
||||
}}
|
||||
>
|
||||
{children}
|
||||
</Box>
|
||||
)
|
||||
}
|
||||
|
||||
export default Description
|
||||
@@ -0,0 +1,45 @@
|
||||
import React from "react"
|
||||
import { Flex, Text } from "theme-ui"
|
||||
import CodeBox from "./code-box"
|
||||
|
||||
const EndpointContainer = ({ endpoints }) => {
|
||||
if (!endpoints) return null
|
||||
|
||||
return (
|
||||
<CodeBox header="ENDPOINTS">
|
||||
<Flex
|
||||
py={2}
|
||||
sx={{
|
||||
flexDirection: "column",
|
||||
}}
|
||||
>
|
||||
{endpoints.map((e, i) => {
|
||||
const method = e.method.toUpperCase()
|
||||
const endpoint = e.endpoint
|
||||
return (
|
||||
<Flex
|
||||
key={i}
|
||||
sx={{ fontSize: "0", fontFamily: "monospace", px: "3", py: "2" }}
|
||||
>
|
||||
<Text
|
||||
variant={`labels.${method}`}
|
||||
sx={{
|
||||
width: "55px",
|
||||
textAlign: "right",
|
||||
}}
|
||||
mr={2}
|
||||
>
|
||||
{method}
|
||||
</Text>
|
||||
<Text sx={{ color: "dark" }}>
|
||||
{endpoint.replace(/{(.*?)}/g, ":$1")}
|
||||
</Text>
|
||||
</Flex>
|
||||
)
|
||||
})}
|
||||
</Flex>
|
||||
</CodeBox>
|
||||
)
|
||||
}
|
||||
|
||||
export default EndpointContainer
|
||||
@@ -0,0 +1,31 @@
|
||||
import React from "react"
|
||||
import { Box, Flex } from "theme-ui"
|
||||
import Topbar from "../topbar"
|
||||
import Section from "./section"
|
||||
|
||||
const Content = ({ data, api }) => {
|
||||
return (
|
||||
<Flex
|
||||
sx={{
|
||||
flexDirection: "column",
|
||||
}}
|
||||
>
|
||||
<Topbar data={data} api={api} />
|
||||
<Box
|
||||
sx={{
|
||||
maxHeight: "calc(100vh - 50px)",
|
||||
overflowY: "scroll",
|
||||
"@media screen and (max-width: 848px)": {
|
||||
mt: "50px",
|
||||
},
|
||||
}}
|
||||
>
|
||||
{data.sections.map((s, i) => {
|
||||
return <Section key={i} data={s} />
|
||||
})}
|
||||
</Box>
|
||||
</Flex>
|
||||
)
|
||||
}
|
||||
|
||||
export default Content
|
||||
@@ -0,0 +1,31 @@
|
||||
import React, { useRef, useEffect } from "react"
|
||||
import { Box } from "theme-ui"
|
||||
import "../../prism-medusa-theme/prism.css"
|
||||
import Prism from "prismjs"
|
||||
import "prismjs/components/prism-json"
|
||||
import CodeBox from "./code-box"
|
||||
|
||||
const JsonContainer = ({ json, header }) => {
|
||||
const jsonRef = useRef()
|
||||
|
||||
//INVESTIGATE: @theme-ui/prism might be a better solution
|
||||
useEffect(() => {
|
||||
if (jsonRef.current) {
|
||||
Prism.highlightAllUnder(jsonRef.current)
|
||||
}
|
||||
}, [])
|
||||
|
||||
if (typeof json !== "string" || json === "{}") return null
|
||||
|
||||
return (
|
||||
<Box ref={jsonRef} sx={{ position: "sticky", top: "20px" }}>
|
||||
<CodeBox header={header}>
|
||||
<pre>
|
||||
<code className={"language-json"}>{json}</code>
|
||||
</pre>
|
||||
</CodeBox>
|
||||
</Box>
|
||||
)
|
||||
}
|
||||
|
||||
export default JsonContainer
|
||||
@@ -0,0 +1,110 @@
|
||||
import React, { useContext, useEffect, useRef } from "react"
|
||||
import Markdown from "react-markdown"
|
||||
import { Flex, Text, Box, Heading } from "theme-ui"
|
||||
import { convertToKebabCase } from "../../utils/convert-to-kebab-case"
|
||||
import Parameters from "./parameters"
|
||||
import Route from "./route"
|
||||
import JsonContainer from "./json-container"
|
||||
import Description from "./description"
|
||||
import ResponsiveContainer from "./responsive-container"
|
||||
import { formatMethodParams } from "../../utils/format-parameters"
|
||||
import useInView from "../../hooks/use-in-view"
|
||||
import NavigationContext from "../../context/navigation-context"
|
||||
|
||||
const Method = ({ data, section, pathname }) => {
|
||||
const { parameters, requestBody, description, method, summary } = data
|
||||
const jsonResponse = data.responses[0].content?.[0].json
|
||||
const { updateHash, updateMetadata } = useContext(NavigationContext)
|
||||
const methodRef = useRef(null)
|
||||
|
||||
const [containerRef, isInView] = useInView({
|
||||
root: null,
|
||||
rootMargin: "0px 0px -80% 0px",
|
||||
threshold: 0,
|
||||
})
|
||||
|
||||
useEffect(() => {
|
||||
if (isInView) {
|
||||
updateHash(section, convertToKebabCase(summary))
|
||||
}
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [isInView])
|
||||
|
||||
const handleMetaChange = () => {
|
||||
updateMetadata({
|
||||
title: summary,
|
||||
description: description,
|
||||
})
|
||||
if (methodRef.current) {
|
||||
methodRef.current.scrollIntoView({
|
||||
behavior: "smooth",
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<Flex
|
||||
py={"5vw"}
|
||||
sx={{
|
||||
borderTop: "hairline",
|
||||
flexDirection: "column",
|
||||
}}
|
||||
id={convertToKebabCase(summary)}
|
||||
ref={methodRef}
|
||||
>
|
||||
<Flex>
|
||||
<Heading
|
||||
as="h2"
|
||||
mb={4}
|
||||
sx={{
|
||||
fontSize: "4",
|
||||
fontWeight: "500",
|
||||
cursor: "pointer",
|
||||
}}
|
||||
ref={containerRef}
|
||||
onClick={() => handleMetaChange()}
|
||||
>
|
||||
{summary}
|
||||
</Heading>
|
||||
</Flex>
|
||||
<ResponsiveContainer>
|
||||
<Flex
|
||||
className="info"
|
||||
sx={{
|
||||
flexDirection: "column",
|
||||
pr: "5",
|
||||
"@media screen and (max-width: 848px)": {
|
||||
pr: "0",
|
||||
},
|
||||
}}
|
||||
>
|
||||
<Route path={pathname} method={method} />
|
||||
<Description>
|
||||
<Text
|
||||
sx={{
|
||||
lineHeight: "26px",
|
||||
}}
|
||||
mt={3}
|
||||
>
|
||||
<Markdown>{description}</Markdown>
|
||||
</Text>
|
||||
</Description>
|
||||
<Box mt={4}>
|
||||
<Parameters
|
||||
params={formatMethodParams({ parameters, requestBody })}
|
||||
/>
|
||||
</Box>
|
||||
</Flex>
|
||||
<Box className="code">
|
||||
<JsonContainer
|
||||
json={jsonResponse}
|
||||
header={"RESPONSE"}
|
||||
method={convertToKebabCase(summary)}
|
||||
/>
|
||||
</Box>
|
||||
</ResponsiveContainer>
|
||||
</Flex>
|
||||
)
|
||||
}
|
||||
|
||||
export default Method
|
||||
@@ -0,0 +1,68 @@
|
||||
import React from "react"
|
||||
import { Flex, Text, Box } from "theme-ui"
|
||||
import Markdown from "react-markdown"
|
||||
import NestedCollapsible from "./collapsible"
|
||||
import Description from "./description"
|
||||
|
||||
const Parameters = ({ params, type }) => {
|
||||
return (
|
||||
<Flex
|
||||
sx={{
|
||||
flexDirection: "column",
|
||||
}}
|
||||
>
|
||||
<Text pb="2">{type === "attr" ? "Attributes" : "Parameters"}</Text>
|
||||
{params.properties.length > 0 ? (
|
||||
params.properties.map((prop, i) => {
|
||||
const nested = prop.nestedModel || prop.items?.properties || null
|
||||
return (
|
||||
<Box
|
||||
py={2}
|
||||
sx={{
|
||||
borderTop: "hairline",
|
||||
fontFamily: "monospace",
|
||||
fontSize: "0",
|
||||
}}
|
||||
key={i}
|
||||
>
|
||||
<Flex sx={{ alignItems: "baseline", fontSize: "0" }}>
|
||||
<Text mr={2}>{prop.property || prop.name}</Text>
|
||||
<Text color={"gray"}>
|
||||
{prop.type || prop.schema?.type || nested?.title}
|
||||
</Text>
|
||||
{prop.required ? (
|
||||
<Text ml={1} variant="labels.required">
|
||||
required
|
||||
</Text>
|
||||
) : null}
|
||||
</Flex>
|
||||
<Description>
|
||||
<Text
|
||||
sx={{
|
||||
fontSize: "0",
|
||||
lineHeight: "26px",
|
||||
fontFamily: "body",
|
||||
}}
|
||||
>
|
||||
<Markdown>{prop.description}</Markdown>
|
||||
</Text>
|
||||
</Description>
|
||||
{nested?.properties && (
|
||||
<NestedCollapsible
|
||||
properties={nested.properties}
|
||||
title={nested.title}
|
||||
/>
|
||||
)}
|
||||
</Box>
|
||||
)
|
||||
})
|
||||
) : (
|
||||
<Text sx={{ fontSize: "0", py: "3", fontFamily: "monospace" }}>
|
||||
No parameters
|
||||
</Text>
|
||||
)}
|
||||
</Flex>
|
||||
)
|
||||
}
|
||||
|
||||
export default Parameters
|
||||
@@ -0,0 +1,29 @@
|
||||
import React from "react"
|
||||
import styled from "@emotion/styled"
|
||||
import { Flex } from "theme-ui"
|
||||
|
||||
const ResponsiveFlex = styled(Flex)`
|
||||
.info {
|
||||
width: 55%;
|
||||
}
|
||||
|
||||
.code {
|
||||
width: 45%;
|
||||
}
|
||||
|
||||
@media screen and (max-width: 848px) {
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
|
||||
.info,
|
||||
.code {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
`
|
||||
|
||||
const ResponsiveContainer = ({ children }) => {
|
||||
return <ResponsiveFlex>{children}</ResponsiveFlex>
|
||||
}
|
||||
|
||||
export default ResponsiveContainer
|
||||
@@ -0,0 +1,17 @@
|
||||
import React from "react"
|
||||
import { Flex, Text } from "theme-ui"
|
||||
import { formatRoute } from "../../utils/format-route"
|
||||
|
||||
const Route = ({ method, path }) => {
|
||||
const fixedMethod = method.toUpperCase()
|
||||
return (
|
||||
<Flex sx={{ fontFamily: "monospace" }}>
|
||||
<Text variant={`labels.${fixedMethod}`} mr={1}>
|
||||
{fixedMethod}
|
||||
</Text>
|
||||
<Text>{formatRoute(path)}</Text>
|
||||
</Flex>
|
||||
)
|
||||
}
|
||||
|
||||
export default Route
|
||||
@@ -0,0 +1,205 @@
|
||||
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 ChevronDown from "../icons/chevron-down"
|
||||
import useInView from "../../hooks/use-in-view"
|
||||
|
||||
const Section = ({ data }) => {
|
||||
const { section } = data
|
||||
const [isExpanded, setIsExpanded] = useState(false)
|
||||
const { openSections, updateSection, updateMetadata } = useContext(
|
||||
NavigationContext
|
||||
)
|
||||
|
||||
const endpoints = section.paths
|
||||
.map(p => {
|
||||
let path = p.name
|
||||
let ep = []
|
||||
|
||||
p.methods.forEach(m => {
|
||||
ep.push({ method: m.method, endpoint: path })
|
||||
})
|
||||
|
||||
return ep
|
||||
})
|
||||
.flat()
|
||||
|
||||
const sectionRef = useRef(null)
|
||||
|
||||
const scrollIntoView = () => {
|
||||
if (sectionRef.current) {
|
||||
sectionRef.current.scrollIntoView({
|
||||
behavior: "smooth",
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
const handleExpand = () => {
|
||||
updateMetadata({
|
||||
title: section.section_name,
|
||||
description: section.schema?.description,
|
||||
})
|
||||
setIsExpanded(true)
|
||||
scrollIntoView()
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
if (isExpanded) {
|
||||
scrollIntoView()
|
||||
}
|
||||
}, [isExpanded])
|
||||
|
||||
useEffect(() => {
|
||||
const shouldOpen = openSections.includes(
|
||||
convertToKebabCase(section.section_name)
|
||||
)
|
||||
|
||||
if (shouldOpen) {
|
||||
setIsExpanded(true)
|
||||
}
|
||||
}, [section.section_name, openSections, openSections.length])
|
||||
|
||||
const [containerRef, isInView] = useInView({
|
||||
root: null,
|
||||
rootMargin: "0px 0px -80% 0px",
|
||||
threshold: 1.0,
|
||||
})
|
||||
|
||||
useEffect(() => {
|
||||
const handleInView = () => {
|
||||
if (isInView) {
|
||||
updateSection(convertToKebabCase(section.section_name))
|
||||
}
|
||||
}
|
||||
handleInView()
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [isInView])
|
||||
|
||||
return (
|
||||
<section ref={sectionRef} id={convertToKebabCase(section.section_name)}>
|
||||
<Box
|
||||
sx={{
|
||||
borderBottom: "hairline",
|
||||
padding: "5vw",
|
||||
backgroundColor: isExpanded ? "transparent" : "fadedContrast",
|
||||
}}
|
||||
>
|
||||
<Flex>
|
||||
<Heading
|
||||
as="h1"
|
||||
sx={{
|
||||
fontWeight: "500",
|
||||
fontSize: "22",
|
||||
mb: "3",
|
||||
cursor: "pointer",
|
||||
}}
|
||||
ref={containerRef}
|
||||
className={`header-${convertToKebabCase(section.section_name)}`}
|
||||
onClick={handleExpand}
|
||||
>
|
||||
{section.section_name}
|
||||
</Heading>
|
||||
</Flex>
|
||||
<Flex
|
||||
sx={{
|
||||
flexDirection: "column",
|
||||
}}
|
||||
>
|
||||
<ResponsiveContainer>
|
||||
<Flex
|
||||
sx={{
|
||||
flexDirection: "column",
|
||||
lineHeight: "26px",
|
||||
pr: "5",
|
||||
"@media screen and (max-width: 848px)": {
|
||||
pr: "0",
|
||||
},
|
||||
}}
|
||||
className="info"
|
||||
>
|
||||
<Description>
|
||||
<Text mb={4}>
|
||||
<Markdown>{section.schema?.description}</Markdown>
|
||||
</Text>
|
||||
</Description>
|
||||
{isExpanded && section.schema ? (
|
||||
<Parameters params={section.schema} type={"attr"} />
|
||||
) : null}
|
||||
</Flex>
|
||||
<Flex
|
||||
className="code"
|
||||
sx={{
|
||||
flexDirection: "column",
|
||||
}}
|
||||
>
|
||||
<EndpointContainer endpoints={endpoints} />
|
||||
{isExpanded ? (
|
||||
<JsonContainer
|
||||
json={section.schema?.object}
|
||||
header={`${section.section_name.toUpperCase()} OBJECT`}
|
||||
/>
|
||||
) : null}
|
||||
</Flex>
|
||||
</ResponsiveContainer>
|
||||
{isExpanded ? (
|
||||
<Box mt={4}>
|
||||
{section.paths.map((p, i) => {
|
||||
return (
|
||||
<Flex
|
||||
key={i}
|
||||
sx={{
|
||||
flexDirection: "column",
|
||||
}}
|
||||
>
|
||||
{p.methods.map((m, i) => {
|
||||
return (
|
||||
<Method
|
||||
key={i}
|
||||
data={m}
|
||||
section={convertToKebabCase(section.section_name)}
|
||||
pathname={p.name}
|
||||
/>
|
||||
)
|
||||
})}
|
||||
</Flex>
|
||||
)
|
||||
})}
|
||||
</Box>
|
||||
) : (
|
||||
<Flex
|
||||
sx={{
|
||||
justifyContent: "center",
|
||||
alignItems: "center",
|
||||
width: "100%",
|
||||
}}
|
||||
mt={4}
|
||||
>
|
||||
<Button
|
||||
onClick={handleExpand}
|
||||
sx={{
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
borderRadius: "24px",
|
||||
bg: "light",
|
||||
fontWeight: "500",
|
||||
}}
|
||||
>
|
||||
SHOW <ChevronDown fill={"dark"} styles={{ mr: "-10px" }} />
|
||||
</Button>
|
||||
</Flex>
|
||||
)}
|
||||
</Flex>
|
||||
</Box>
|
||||
</section>
|
||||
)
|
||||
}
|
||||
|
||||
export default Section
|
||||
Reference in New Issue
Block a user