docs: oas (#197)
Adds OpenAPI specification of Storefront and Admin APIs. Updates docs project.
This commit is contained in:
@@ -0,0 +1,88 @@
|
||||
import React from "react"
|
||||
import { Flex, Box, Text } from "rebass"
|
||||
import styled from "@emotion/styled"
|
||||
import Markdown from "react-markdown"
|
||||
|
||||
import RouteSection from "./route-section"
|
||||
import JsonBox from "./json-box"
|
||||
import EndpointOverview from "./endpoint-overview"
|
||||
import Parameters from "./parameters"
|
||||
|
||||
const convertToKebabCase = string => {
|
||||
return string.replace(/\s+/g, "-").toLowerCase()
|
||||
}
|
||||
|
||||
const EndpointContainer = styled(Flex)`
|
||||
min-height: 90vh;
|
||||
position: relative;
|
||||
border-top: hairline;
|
||||
|
||||
code {
|
||||
background-color: #e3e8ee;
|
||||
border-radius: 5px;
|
||||
padding: 4px;
|
||||
}
|
||||
`
|
||||
|
||||
const DocsReader = ({ tags, spec }) => {
|
||||
return (
|
||||
<Flex flexDirection="column" width="100%">
|
||||
{Object.entries(tags).map(([tagName, endpoints]) => (
|
||||
<EndpointContainer id={convertToKebabCase(tagName)} p={4}>
|
||||
<Flex flexDirection="row" width="100%">
|
||||
<Flex py={5} flexDirection="column" p={4} width="100%">
|
||||
<EndpointOverview
|
||||
title={tagName}
|
||||
description={""}
|
||||
routes={endpoints}
|
||||
spec={spec}
|
||||
/>
|
||||
<Flex
|
||||
flexDirection="row"
|
||||
width={"100%"}
|
||||
sx={{
|
||||
position: "relative",
|
||||
borderTop: "hairline",
|
||||
}}
|
||||
>
|
||||
<Flex width={"100%"} flexDirection="column">
|
||||
{endpoints.map((endpoint, i) => (
|
||||
<Flex
|
||||
id={convertToKebabCase(endpoint.summary)}
|
||||
py={4}
|
||||
flexDirection="row"
|
||||
width="100%"
|
||||
>
|
||||
<Flex
|
||||
pr={5}
|
||||
width={"55%"}
|
||||
flexDirection="column"
|
||||
sx={{ lineHeight: "26px" }}
|
||||
>
|
||||
<Text mb={3} fontSize={3}>
|
||||
{endpoint.summary}
|
||||
</Text>
|
||||
<RouteSection
|
||||
basePath={""}
|
||||
method={endpoint.method}
|
||||
path={endpoint.path}
|
||||
/>
|
||||
<Markdown>{endpoint.description}</Markdown>
|
||||
<Parameters endpoint={endpoint} />
|
||||
</Flex>
|
||||
<Flex py={5} width="45%" flex="1">
|
||||
<JsonBox name={tagName} endpoint={endpoint} />
|
||||
</Flex>
|
||||
</Flex>
|
||||
))}
|
||||
</Flex>
|
||||
</Flex>
|
||||
</Flex>
|
||||
</Flex>
|
||||
</EndpointContainer>
|
||||
))}
|
||||
</Flex>
|
||||
)
|
||||
}
|
||||
|
||||
export default DocsReader
|
||||
@@ -0,0 +1,65 @@
|
||||
import React from "react"
|
||||
import { Flex, Box, Text } from "rebass"
|
||||
|
||||
import RoutesOverview from "./routes-overview"
|
||||
import ParamSection from "./param-section"
|
||||
import JsonBox from "./json-box"
|
||||
|
||||
const EndpointOverview = ({ title, description, routes, spec }) => {
|
||||
let schema = {}
|
||||
let attrs = []
|
||||
let resourceId
|
||||
|
||||
if (spec) {
|
||||
const tag = spec.tags.find(t => t.name === title)
|
||||
|
||||
if (tag && tag["x-resourceId"]) {
|
||||
resourceId = tag["x-resourceId"]
|
||||
schema = spec.components.schemas[tag["x-resourceId"]]
|
||||
|
||||
for (const [name, details] of Object.entries(schema.properties)) {
|
||||
if (!attrs.find(a => a.name === name)) {
|
||||
attrs.push({
|
||||
name,
|
||||
...details,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<Flex flexDirection="row" pb={4}>
|
||||
<Flex
|
||||
flexDirection="column"
|
||||
width="55%"
|
||||
pr={5}
|
||||
sx={{ lineHeight: "26px" }}
|
||||
>
|
||||
<Text mb={3} fontSize={4}>
|
||||
{title}
|
||||
</Text>
|
||||
<Text mb={4}>{description || schema.description}</Text>
|
||||
{attrs.length > 0 && (
|
||||
<Box
|
||||
sx={{
|
||||
borderBottom: "hairline",
|
||||
}}
|
||||
my="2"
|
||||
>
|
||||
<Text my={2}>Attributes</Text>
|
||||
{attrs.map(p => (
|
||||
<ParamSection param={p} />
|
||||
))}
|
||||
</Box>
|
||||
)}
|
||||
</Flex>
|
||||
<Flex width={"45%"} flexDirection="column">
|
||||
{routes && <RoutesOverview content={routes} />}
|
||||
{resourceId && <JsonBox text={"OBJECT"} resourceId={resourceId} />}
|
||||
</Flex>
|
||||
</Flex>
|
||||
)
|
||||
}
|
||||
|
||||
export default EndpointOverview
|
||||
@@ -0,0 +1,88 @@
|
||||
import React, { useState, useEffect } from "react"
|
||||
import { graphql } from "gatsby"
|
||||
import { Flex, Box, Text, Image } from "rebass"
|
||||
import styled from "@emotion/styled"
|
||||
import { AnchorLink } from "gatsby-plugin-anchor-links"
|
||||
import Markdown from "react-markdown"
|
||||
import Highlight from "react-highlight.js"
|
||||
|
||||
import "highlight.js/styles/a11y-light.css"
|
||||
|
||||
import fixtures from "../../../docs/api/fixtures.json"
|
||||
|
||||
export const ResponseContainer = styled(Flex)`
|
||||
border: 1px solid #e3e8ee;
|
||||
border-radius: 5px;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
width: 100%;
|
||||
max-height: calc(90vh - 20px);
|
||||
overflow-y: scroll;
|
||||
align-self: flex-start;
|
||||
font-size: 1;
|
||||
position: sticky;
|
||||
top: 20px;
|
||||
|
||||
code {
|
||||
background: #f7fafc !important;
|
||||
}
|
||||
`
|
||||
|
||||
const JsonBox = ({ text, resourceId, endpoint }) => {
|
||||
const [json, setJson] = useState({})
|
||||
|
||||
useEffect(() => {
|
||||
const toSet = {}
|
||||
if (endpoint) {
|
||||
const props =
|
||||
endpoint?.responses?.["200"]?.content?.["application/json"]?.schema
|
||||
?.properties
|
||||
|
||||
if (props) {
|
||||
for (const [name, details] of Object.entries(props)) {
|
||||
if (
|
||||
details["x-resourceId"] &&
|
||||
details["x-resourceId"] in fixtures.resources
|
||||
) {
|
||||
toSet[name] = fixtures.resources[details["x-resourceId"]]
|
||||
} else {
|
||||
toSet[name] = details
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (resourceId) {
|
||||
setJson(fixtures.resources[resourceId])
|
||||
} else {
|
||||
setJson(toSet)
|
||||
}
|
||||
}, [])
|
||||
|
||||
return (
|
||||
<ResponseContainer flexDirection="column" as="pre">
|
||||
<Text
|
||||
fontSize={0}
|
||||
fontFamily="body"
|
||||
py={2}
|
||||
px={3}
|
||||
color="#4f566b"
|
||||
backgroundColor="#e3e8ee"
|
||||
>
|
||||
{text || "RESPONSE"}
|
||||
</Text>
|
||||
<Box
|
||||
w={1}
|
||||
flex="1"
|
||||
sx={{ overflowY: "scroll" }}
|
||||
backgroundColor="#f7fafc"
|
||||
>
|
||||
<Highlight language="json">
|
||||
{JSON.stringify(json, undefined, 2)}
|
||||
</Highlight>
|
||||
</Box>
|
||||
</ResponseContainer>
|
||||
)
|
||||
}
|
||||
|
||||
export default JsonBox
|
||||
@@ -0,0 +1,145 @@
|
||||
import React from "react"
|
||||
import styled from "@emotion/styled"
|
||||
import { Flex, Box, Text } from "rebass"
|
||||
import Markdown from "react-markdown"
|
||||
import Collapsible from "react-collapsible"
|
||||
|
||||
const ExpandContainer = styled.div`
|
||||
.child-attrs {
|
||||
cursor: pointer;
|
||||
font-size: 12px;
|
||||
box-sizing: border-box;
|
||||
padding-left: 10px;
|
||||
padding-right: 10px;
|
||||
width: max-content;
|
||||
border-radius: 5px;
|
||||
border: 1px solid #e3e8ee;
|
||||
color: #afafaf;
|
||||
|
||||
&:hover {
|
||||
color: #212121;
|
||||
}
|
||||
}
|
||||
.child-attrs.is-open {
|
||||
width: 100%;
|
||||
border-bottom: none;
|
||||
border-bottom-left-radius: 0;
|
||||
border-bottom-right-radius: 0;
|
||||
}
|
||||
`
|
||||
|
||||
const Expand = ({ schema }) => {
|
||||
const properties = schema.properties
|
||||
|
||||
let aggregated = []
|
||||
for (const [name, details] of Object.entries(properties)) {
|
||||
if (!aggregated.find(a => a.name === name)) {
|
||||
aggregated.push({
|
||||
name,
|
||||
...details,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<ExpandContainer>
|
||||
<Collapsible
|
||||
transitionTime={50}
|
||||
triggerClassName={"child-attrs"}
|
||||
triggerOpenedClassName={"child-attrs"}
|
||||
triggerTagName="div"
|
||||
trigger={"Show nested attributes"}
|
||||
triggerWhenOpen={"Hide"}
|
||||
>
|
||||
<Box
|
||||
sx={{
|
||||
padding: "10px",
|
||||
borderRadius: "5px",
|
||||
borderTopLeftRadius: 0,
|
||||
borderTopRightRadius: 0,
|
||||
border: "hairline",
|
||||
}}
|
||||
mb="2"
|
||||
>
|
||||
<Text my={2}>{schema.title}</Text>
|
||||
{aggregated.map(param => {
|
||||
let type = param.type
|
||||
if (!type && param.schema) {
|
||||
type = param.schema.type
|
||||
}
|
||||
return (
|
||||
<Box
|
||||
py={2}
|
||||
sx={{
|
||||
borderTop: "hairline",
|
||||
}}
|
||||
>
|
||||
<Flex
|
||||
fontSize="1"
|
||||
alignItems="baseline"
|
||||
pb={1}
|
||||
fontFamily="monospace"
|
||||
>
|
||||
<Box mr={2} fontSize={"12px"}>
|
||||
{param.name}
|
||||
</Box>
|
||||
<Text color={"gray"} fontSize={"10px"}>
|
||||
{type}
|
||||
</Text>
|
||||
{param.required && (
|
||||
<Text ml={1} fontSize={"10px"} variant="labels.required">
|
||||
required
|
||||
</Text>
|
||||
)}
|
||||
</Flex>
|
||||
<Text fontSize={0}>
|
||||
<Markdown>{param.description}</Markdown>
|
||||
</Text>
|
||||
</Box>
|
||||
)
|
||||
})}
|
||||
</Box>
|
||||
</Collapsible>
|
||||
</ExpandContainer>
|
||||
)
|
||||
}
|
||||
|
||||
const ParamSection = ({ routeParam, param }) => {
|
||||
let type = param.type
|
||||
if (!type && param.schema) {
|
||||
type = param.schema.type
|
||||
}
|
||||
|
||||
return (
|
||||
<Box
|
||||
py={2}
|
||||
sx={{
|
||||
borderTop: "hairline",
|
||||
}}
|
||||
>
|
||||
<Flex fontSize="1" alignItems="baseline" pb={1} fontFamily="monospace">
|
||||
<Box mr={2} fontSize={"12px"}>
|
||||
{param.name}
|
||||
</Box>
|
||||
<Text color={"gray"} fontSize={"10px"}>
|
||||
{type}
|
||||
</Text>
|
||||
{(param.required || routeParam) && (
|
||||
<Text ml={1} fontSize={"10px"} variant="labels.required">
|
||||
required
|
||||
</Text>
|
||||
)}
|
||||
</Flex>
|
||||
<Text fontSize={0}>
|
||||
<Markdown>{param.description}</Markdown>
|
||||
</Text>
|
||||
{param.anyOf && param.anyOf.map(schema => <Expand schema={schema} />)}
|
||||
{param.oneOf && param.oneOf.map(schema => <Expand schema={schema} />)}
|
||||
{param.type === "array" && param.items?.properties && (
|
||||
<Expand schema={param.items} />
|
||||
)}
|
||||
</Box>
|
||||
)
|
||||
}
|
||||
|
||||
export default ParamSection
|
||||
@@ -0,0 +1,41 @@
|
||||
import React from "react"
|
||||
import { Flex, Box, Text } from "rebass"
|
||||
|
||||
import ParamSection from "./param-section"
|
||||
|
||||
const Parameters = ({ endpoint }) => {
|
||||
const aggregated = endpoint.parameters || []
|
||||
|
||||
const reqBody = endpoint.requestBody || {}
|
||||
const props = reqBody.content?.["application/json"]?.schema?.properties
|
||||
if (props) {
|
||||
for (const [name, details] of Object.entries(props)) {
|
||||
if (!aggregated.find(a => a.name === name)) {
|
||||
aggregated.push({
|
||||
name,
|
||||
...details,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!aggregated.length) {
|
||||
return null
|
||||
}
|
||||
|
||||
return (
|
||||
<Box
|
||||
sx={{
|
||||
borderBottom: "hairline",
|
||||
}}
|
||||
my="2"
|
||||
>
|
||||
<Text my={2}>Parameters</Text>
|
||||
{aggregated.map(p => (
|
||||
<ParamSection param={p} />
|
||||
))}
|
||||
</Box>
|
||||
)
|
||||
}
|
||||
|
||||
export default Parameters
|
||||
@@ -0,0 +1,19 @@
|
||||
import React from "react"
|
||||
import { Flex, Box, Text } from "rebass"
|
||||
|
||||
const RouteSection = ({ basePath, path, method }) => {
|
||||
path = path.replaceAll(/{(.*?)}/g, ":$1")
|
||||
|
||||
return (
|
||||
<Box py={2}>
|
||||
<Flex fontFamily="monospace">
|
||||
<Text mr={2} variant={`labels.${method}`}>
|
||||
{method}
|
||||
</Text>
|
||||
<Text>{`${basePath}${path === "/" ? "" : path}`}</Text>
|
||||
</Flex>
|
||||
</Box>
|
||||
)
|
||||
}
|
||||
|
||||
export default RouteSection
|
||||
@@ -0,0 +1,64 @@
|
||||
import React, { useState, useEffect } from "react"
|
||||
import styled from "@emotion/styled"
|
||||
import { Flex, Box, Text, Image } from "rebass"
|
||||
|
||||
const StyledRoutesOverview = styled(Flex)`
|
||||
border: 1px solid #e3e8ee;
|
||||
border-radius: 5px;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
width: 100%;
|
||||
max-height: calc(90vh - 20px);
|
||||
overflow-y: scroll;
|
||||
align-self: flex-start;
|
||||
font-size: 1;
|
||||
top: 20px;
|
||||
bottom: 20px;
|
||||
`
|
||||
|
||||
const RoutesOverview = ({ content }) => {
|
||||
if (!content) return null
|
||||
|
||||
return (
|
||||
<StyledRoutesOverview mb={3} flexDirection="column">
|
||||
<Text
|
||||
fontSize={0}
|
||||
fontFamily="body"
|
||||
py={2}
|
||||
px={3}
|
||||
color="#4f566b"
|
||||
backgroundColor="#e3e8ee"
|
||||
>
|
||||
ENDPOINTS
|
||||
</Text>
|
||||
<Box
|
||||
w={1}
|
||||
px={4}
|
||||
py={2}
|
||||
flex="1"
|
||||
sx={{ overflowY: "scroll" }}
|
||||
backgroundColor="#f7fafc"
|
||||
>
|
||||
<Flex fontSize={1} flexDirection="column">
|
||||
{content.map(route => (
|
||||
<Flex mb={2} width="100%">
|
||||
<Text
|
||||
width="55px"
|
||||
mr={2}
|
||||
variant={`labels.${route.method}`}
|
||||
textAlign="right"
|
||||
>
|
||||
{route.method}
|
||||
</Text>
|
||||
<Text color="#4f566b">
|
||||
{route.path.replaceAll(/{(.*?)}/g, ":$1")}
|
||||
</Text>
|
||||
</Flex>
|
||||
))}
|
||||
</Flex>
|
||||
</Box>
|
||||
</StyledRoutesOverview>
|
||||
)
|
||||
}
|
||||
|
||||
export default RoutesOverview
|
||||
@@ -0,0 +1,107 @@
|
||||
import React from "react"
|
||||
import { Flex } from "rebass"
|
||||
import { Label, Select as RebassSelect } from "@rebass/forms"
|
||||
import styled from "@emotion/styled"
|
||||
|
||||
import Typography from "./typography"
|
||||
|
||||
const StyledSelect = styled(RebassSelect)`
|
||||
${Typography.Base}
|
||||
padding-right: 28px;
|
||||
|
||||
${props =>
|
||||
props.isCurrencyInput &&
|
||||
`
|
||||
box-shadow: none;
|
||||
border: none;
|
||||
|
||||
&:hover {
|
||||
box-shadow: none;
|
||||
}
|
||||
`}
|
||||
`
|
||||
|
||||
const StyledLabel = styled.div`
|
||||
${Typography.Base}
|
||||
${props =>
|
||||
props.inline
|
||||
? `
|
||||
text-align: right;
|
||||
padding-right: 15px;
|
||||
`
|
||||
: `
|
||||
padding-bottom: 10px;
|
||||
`}
|
||||
|
||||
${props =>
|
||||
props.required &&
|
||||
`
|
||||
&:after {
|
||||
color: rgba(255, 0, 0, 0.5);
|
||||
content: " *";
|
||||
}
|
||||
`}
|
||||
`
|
||||
|
||||
const Select = React.forwardRef(
|
||||
(
|
||||
{
|
||||
name = "",
|
||||
label = "",
|
||||
defaultValue = "",
|
||||
options = [],
|
||||
placeholder = "",
|
||||
value,
|
||||
onChange,
|
||||
inline,
|
||||
required,
|
||||
selectHeight,
|
||||
isCurrencyInput,
|
||||
...props
|
||||
},
|
||||
ref
|
||||
) => {
|
||||
return (
|
||||
<Flex
|
||||
alignItems={inline && "center"}
|
||||
flexDirection={inline ? "row" : "column"}
|
||||
{...props}
|
||||
>
|
||||
{label && (
|
||||
<Label
|
||||
flex={"30% 0 0"}
|
||||
maxWidth={"200px"}
|
||||
htmlFor={name}
|
||||
display={props.start ? "flex" : inline && "inline !important"}
|
||||
>
|
||||
<StyledLabel required={required} inline={inline}>
|
||||
{label}
|
||||
</StyledLabel>
|
||||
</Label>
|
||||
)}
|
||||
<StyledSelect
|
||||
isCurrencyInput={isCurrencyInput}
|
||||
flex="50% 0 0"
|
||||
variant="buttons.primary"
|
||||
name={name}
|
||||
height={selectHeight || "inherit"}
|
||||
minWidth={"unset"}
|
||||
width={"unset"}
|
||||
ref={ref}
|
||||
value={value}
|
||||
defaultValue={defaultValue}
|
||||
onChange={onChange}
|
||||
>
|
||||
{placeholder && <option>{placeholder}</option>}
|
||||
{options.map((option, index) => (
|
||||
<option key={index} value={option.value}>
|
||||
{option.label || option.value}
|
||||
</option>
|
||||
))}
|
||||
</StyledSelect>
|
||||
</Flex>
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
export default Select
|
||||
@@ -0,0 +1,136 @@
|
||||
import React, { useState, useEffect } from "react"
|
||||
import { Link, navigate } from "gatsby"
|
||||
import { Flex, Box, Text } from "rebass"
|
||||
import { AnchorLink } from "gatsby-plugin-anchor-links"
|
||||
import styled from "@emotion/styled"
|
||||
import Collapsible from "react-collapsible"
|
||||
|
||||
import Select from "./select"
|
||||
|
||||
const convertToKebabCase = string => {
|
||||
return string.replace(/\s+/g, "-").toLowerCase()
|
||||
}
|
||||
|
||||
const StyledNavItem = styled(Flex)`
|
||||
padding-left: 16px;
|
||||
padding-right: 10px;
|
||||
align-items: center;
|
||||
border-radius: 5pt;
|
||||
cursor: pointer;
|
||||
margin-bottom: 5px;
|
||||
height: 25px;
|
||||
|
||||
&:hover {
|
||||
background-color: #e0e0e059;
|
||||
}
|
||||
`
|
||||
|
||||
const StyledAnchorLink = styled(AnchorLink)`
|
||||
display: flex;
|
||||
margin-left: 10px;
|
||||
padding-left: 10px;
|
||||
padding-right: 10px;
|
||||
align-items: center;
|
||||
border-radius: 5pt;
|
||||
cursor: pointer;
|
||||
margin-bottom: 5px;
|
||||
text-decoration: none;
|
||||
align-items: center;
|
||||
color: black;
|
||||
height: 25px;
|
||||
[fill*="red"] {
|
||||
fill: #454545;
|
||||
}
|
||||
&:hover {
|
||||
${props =>
|
||||
!props.active &&
|
||||
`
|
||||
background-color: #e0e0e059;
|
||||
`}
|
||||
}
|
||||
&.active {
|
||||
background-color: #e0e0e0;
|
||||
}
|
||||
`
|
||||
|
||||
const SideBarContainer = styled(Flex)`
|
||||
position: sticky;
|
||||
top: 0;
|
||||
height: 100vh;
|
||||
overflow-y: scroll;
|
||||
background-color: #f0f0f0;
|
||||
min-width: 250px;
|
||||
flex-direction: column;
|
||||
`
|
||||
|
||||
const StyledLink = styled(Link)`
|
||||
color: #212121;
|
||||
font-decoration: none;
|
||||
`
|
||||
|
||||
const SideBar = ({ tags }) => {
|
||||
const [api, setApi] = useState("store")
|
||||
|
||||
useEffect(() => {
|
||||
const pathname = window.location.pathname
|
||||
const matches = pathname.match(/api\/(store|admin)/)
|
||||
if (pathname.length > 1) {
|
||||
setApi(matches[1])
|
||||
}
|
||||
}, [])
|
||||
|
||||
return (
|
||||
<SideBarContainer>
|
||||
<Flex
|
||||
width="100%"
|
||||
alignContent="center"
|
||||
justifyContent={"center"}
|
||||
sx={{ borderBottom: "hairline" }}
|
||||
px={4}
|
||||
py={3}
|
||||
mb={3}
|
||||
justifyContent="center"
|
||||
flexDirection="column"
|
||||
>
|
||||
<Flex width={"100%"} alignContent="center">
|
||||
<Text
|
||||
fontFamily="Medusa"
|
||||
fontSize="26px"
|
||||
color="#454b54"
|
||||
fontWeight={300}
|
||||
>
|
||||
medusa
|
||||
</Text>
|
||||
</Flex>
|
||||
<Flex pt={3} justifyContent="space-between">
|
||||
<Select
|
||||
value={api}
|
||||
onChange={e => navigate(`/api/${e.target.value}`)}
|
||||
options={[
|
||||
{ value: "admin", label: "Admin" },
|
||||
{ value: "store", label: "Storefront" },
|
||||
]}
|
||||
/>
|
||||
</Flex>
|
||||
</Flex>
|
||||
{Object.entries(tags).map(([tag, details]) => {
|
||||
return (
|
||||
<Box pt={1} px={3}>
|
||||
<Collapsible
|
||||
transitionTime={50}
|
||||
trigger={<StyledNavItem fontSize={1}>{tag}</StyledNavItem>}
|
||||
>
|
||||
{details.map(e => (
|
||||
<StyledAnchorLink to={`#${convertToKebabCase(e.summary)}`}>
|
||||
<Text fontSize={0}>{e.summary}</Text>
|
||||
</StyledAnchorLink>
|
||||
))}
|
||||
</Collapsible>
|
||||
</Box>
|
||||
)
|
||||
})}
|
||||
</SideBarContainer>
|
||||
)
|
||||
}
|
||||
|
||||
export default SideBar
|
||||
@@ -0,0 +1,54 @@
|
||||
import { css } from "@emotion/core"
|
||||
|
||||
const Largest = props => css`
|
||||
font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Roboto,
|
||||
Helvetica Neue, Ubuntu, sans-serif;
|
||||
font-size: 22px;
|
||||
font-weight: 300;
|
||||
line-height: 1.5;
|
||||
letter-spacing: normal;
|
||||
`
|
||||
|
||||
const Large = props => css`
|
||||
font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Roboto,
|
||||
Helvetica Neue, Ubuntu, sans-serif;
|
||||
font-size: 18px;
|
||||
font-weight: 300;
|
||||
line-height: 1.22;
|
||||
letter-spacing: -0.5px;
|
||||
`
|
||||
|
||||
const Medium = props => css`
|
||||
font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Roboto,
|
||||
Helvetica Neue, Ubuntu, sans-serif;
|
||||
font-size: 16px;
|
||||
font-weight: 300;
|
||||
line-height: 1.22;
|
||||
letter-spacing: normal;
|
||||
`
|
||||
|
||||
const Base = props => css`
|
||||
font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Roboto,
|
||||
Helvetica Neue, Ubuntu, sans-serif;
|
||||
font-size: 14px;
|
||||
font-weight: 300;
|
||||
line-height: 1.22;
|
||||
letter-spacing: -0.25px;
|
||||
`
|
||||
|
||||
const Small = props => css`
|
||||
font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Roboto,
|
||||
Helvetica Neue, Ubuntu, sans-serif;
|
||||
font-size: 12px;
|
||||
font-weight: 300;
|
||||
line-height: 12px;
|
||||
letter-spacing: 0px;
|
||||
`
|
||||
|
||||
export default {
|
||||
Largest,
|
||||
Large,
|
||||
Medium,
|
||||
Base,
|
||||
Small,
|
||||
}
|
||||
Reference in New Issue
Block a user