From e322203b720e9554a99c6a0cc34033a6774b49b6 Mon Sep 17 00:00:00 2001 From: Ostap Mokhnatskyi Date: Wed, 6 Jul 2022 19:34:06 +0300 Subject: [PATCH] chore: add custom overrides examples --- _override/App.tsx | 19 +++ _override/Footer.tsx | 149 ++++++++++++++++++ _override/MenuItem.tsx | 266 +++++++++++++++++++++++++++++++++ _override/NavBar.tsx | 190 +++++++++++++++++++++++ _override/SearchInput.tsx | 56 +++++++ _override/SearchResults.tsx | 105 +++++++++++++ _override/layouts/Markdown.tsx | 68 +++++++++ _override/layouts/sidebar.tsx | 38 +++++ package.json | 2 +- yarn.lock | 32 ++-- 10 files changed, 907 insertions(+), 18 deletions(-) create mode 100644 _override/App.tsx create mode 100644 _override/Footer.tsx create mode 100644 _override/MenuItem.tsx create mode 100644 _override/NavBar.tsx create mode 100644 _override/SearchInput.tsx create mode 100644 _override/SearchResults.tsx create mode 100644 _override/layouts/Markdown.tsx create mode 100644 _override/layouts/sidebar.tsx diff --git a/_override/App.tsx b/_override/App.tsx new file mode 100644 index 00000000..05fbd344 --- /dev/null +++ b/_override/App.tsx @@ -0,0 +1,19 @@ +import * as React from 'react'; +import type { Location } from 'history'; + +/** + * Root wrapper. + */ +export function App({ children, location }: React.PropsWithChildren<{ location: Location }>) { + return ( + <> + {/* you can add some top-level providers here or anything to wrap whole app */} + + {/*
+ Header +
*/} + + {children} + + ); +} \ No newline at end of file diff --git a/_override/Footer.tsx b/_override/Footer.tsx new file mode 100644 index 00000000..f68ecec7 --- /dev/null +++ b/_override/Footer.tsx @@ -0,0 +1,149 @@ +import * as React from 'react'; +import styled from 'styled-components'; + +import { Box, Flex, Link, FooterProps } from '@redocly/developer-portal/ui'; + +/** + * Custom Navbar. The implementation below is almost identical to our default Footer + */ +export default function CustomFooter(props: FooterProps) { + // you can use columns/copyright values from props, it comes from siteConfig.yaml + // but you can also import it from a separate yaml or json file + const { columns, copyrightText } = props.footer; + const siteVersion = props.siteVersion; + + const columnsElement = columns.length ? ( + + + {columns.map((column, index) => ( + + {column.group || column.label} + + {column.items.map((columnItem, columnItemInex) => + columnItem.type === 'separator' ? ( + {columnItem.label} + ) : ( + + + {columnItem.label} + + + ) + )} + + + ))} + + + ) : null; + + const infoElement = + copyrightText || siteVersion ? ( + + + {copyrightText} {siteVersion ? `| ${siteVersion}` : null} + + + ) : null; + + return ( + + {columnsElement} + {infoElement} + + ); +} + +const FooterColumns = styled(Flex)` + background-color: ${({ theme }) => theme.colors.footer.main}; + color: ${({ theme }) => theme.colors.footer.contrastText}; + font-family: ${({ theme }) => theme.typography.headings.fontFamily}; + + a, + a:hover { + color: ${({ theme }) => theme.colors.footer.contrastText}; + } +`; + +// very important for NavWrapper to be a "footer" HTML tag +const FooterWrapper = styled.footer` + font-size: 1rem; + flex-shrink: 0; + font-family: ${({ theme }) => theme.typography.fontFamily}; + + @media print { + color: black; + ${FooterColumns} { + display: none; + } + } +`; + +export const FooterInfo = styled.section` + display: flex; + justify-content: center; + font-size: 0.875em; + padding: 1.5em 3em; + font-weight: ${({ theme }) => theme.typography.fontWeightBold}; + background-color: ${({ theme }) => theme.colors.footer.main}; + color: ${({ theme }) => theme.colors.footer.contrastText}; + span { + max-width: 1200px; + } +`; + +export const ColumnList = styled.ul` + margin: 0; + padding: 0; + list-style: none; +`; + +export const ColumnListItem = styled.li` + font-weight: ${({ theme }) => theme.typography.fontWeightBold}; + padding-bottom: 0.75em; + a { + color: ${props => props.theme.colors.primary.contrastText}; + text-decoration: none; + } +`; + +export const FooterSeparator = styled.li` + opacity: 0.75; + margin: 10px 0 5px 0; + font-size: 0.75em; + text-transform: uppercase; + font-family: ${({ theme }) => theme.typography.headings.fontFamily}; +`; + +export const FooterCopyright = styled.span` + text-align: center; +`; + +export const ColumnTitle = styled.span` + display: inline-block; + font-weight: ${({ theme }) => theme.typography.fontWeightRegular}; + margin-bottom: 1.5em; + fontfamily: ${({ theme }) => theme.typography.headings.fontFamily}; + + @media only screen and (min-width: ${({ theme }) => theme.breakpoints.large}) { + margin-bottom: 2.5em; + } +`; diff --git a/_override/MenuItem.tsx b/_override/MenuItem.tsx new file mode 100644 index 00000000..85d07b8a --- /dev/null +++ b/_override/MenuItem.tsx @@ -0,0 +1,266 @@ +import * as React from 'react'; +import styled, { useTheme } from 'styled-components'; +import { MenuItemProps, Link, Arrow, OperationBadge, MenuItem } from '@redocly/developer-portal/ui'; + +/** + * You can simply wrap or add css to the existing MenuItem element by importing it + */ + +// import { MenuItem as OriginalMenuItem } from '@redocly/developer-portal/ui'; + +// export default function CustomMenuItem(props: MenuItemProps) { +// return ( +//
+// +//
+// ); +// } + +// const StyledMenuItem = styled(OriginalMenuItem)` +// color: #555; +// `; + +/** + * Custom sidebar MenuItem. The implementation below is almost identical to our default Footer. + * The only difference is it adds a red border for active item. + */ +export default function CustomMenuItem(props: MenuItemProps) { + const { + item: { active, expanded, items, link, label, type, httpVerb, external, target, menuStyle, icon, sublabel }, + depth, + isLast, + isExpanded, + isAlwaysExpanded, + className, + } = props; + + const theme = useTheme(); + const ref = React.useRef(null); + + React.useLayoutEffect(() => { + if (props.item.active) { + const node = ref.current; + if (!node) { + return; + } + + const scrollHeight = document.body.scrollHeight; + const totalHeight = window.scrollY + window.innerHeight; + + // at the bottom of the page + if (totalHeight >= scrollHeight) { + return; + } + + node.scrollIntoView({ + behavior: 'smooth', + block: 'nearest', + }); + } + }); + + const hasChildren = items && items.length > 0; + const arrowDirection = isExpanded ? 'down' : 'right'; + const isDrilldown = menuStyle === 'drilldown'; + const element = + type === 'separator' ? ( + + {label} + + ) : ( + <> + + {hasChildren && !isDrilldown && !isAlwaysExpanded && ( + + + + )} + {httpVerb && ( +
+ {httpVerb} +
+ )} + {isDrilldown ? ( + + ) : ( + {label} + )} + {/* {external && ( +
+ +
+ )} */} +
+ + ); + + return link ? ( + + {element} + + ) : ( + element + ); +} + +export const MenuItemTitle = styled.div<{ + expanded: boolean; + active: boolean; + last: boolean; + isAlwaysExpanded: boolean; + hasChildren: boolean; + isDrilldown: boolean; + depth: number; +}>` + border-left: ${({ active }) => (active ? '4px solid #DC1928' : '4px solid transparent')}; + + position: relative; + display: flex; + justify-content: space-between; + + font-family: ${({ theme }) => theme.sidebar.fontFamily}; + font-size: ${({ theme }) => theme.sidebar.fontSize}; + font-weight: ${({ theme }) => theme.typography.fontWeightRegular}; + + color: ${props => (props.active ? props.theme.sidebar.activeTextColor : 'inherit')}; + background-color: ${props => (props.active ? props.theme.sidebar.activeBgColor : 'inherit')}; + + cursor: ${({ isAlwaysExpanded }) => (isAlwaysExpanded ? 'default' : 'pointer')}; + + margin-left: ${({ depth, theme }) => + `${theme.sidebar.spacing.offsetLeft + depth * theme.sidebar.spacing.offsetNesting}px`}; + + padding-top: ${({ theme }) => theme.sidebar.spacing.paddingVertical}px; + padding-right: ${({ theme }) => theme.sidebar.spacing.paddingHorizontal}px; + padding-bottom: ${({ theme }) => theme.sidebar.spacing.paddingVertical}px; + margin-bottom: 1px; // hardcoded for now + + padding-left: ${ + ({ theme, hasChildren, isAlwaysExpanded }) => + hasChildren && !isAlwaysExpanded + ? theme.sidebar.spacing.paddingHorizontal + : theme.sidebar.spacing.paddingHorizontal + + theme.sidebar.caretSize + + theme.sidebar.spacing.unit * 0.5 /* chevron margin-right = unit 0.5*/ + }px; + + transition: background-color 0.3s, color 0.3s; + border-top-left-radius: ${({ theme }) => theme.sidebar.borderRadius}; + border-bottom-left-radius: ${({ theme }) => theme.sidebar.borderRadius}; + + word-break: break-word; + + :hover { + color: ${({ isAlwaysExpanded, theme }) => (isAlwaysExpanded ? 'inherit' : theme.sidebar.activeTextColor)}; + background-color: ${({ isAlwaysExpanded, theme }) => (isAlwaysExpanded ? 'inherit' : theme.sidebar.activeBgColor)}; + } + + :empty { + padding: 0; + } + + ${({ isDrilldown, theme }) => + isDrilldown && + ` + padding-top: ${theme.sidebar.spacing.paddingVertical * 2}px; + padding-bottom: ${theme.sidebar.spacing.paddingVertical * 2}px; + padding-left: ${theme.sidebar.spacing.paddingHorizontal}px; + &:hover { + color: currentColor; + background-color: ${theme.sidebar.backgroundColor}; + } + `} +`; + +export const Separator = styled.span<{ depth?: number }>` + display: flex; + justify-content: space-between; + margin-left: ${({ theme, depth = 0 }) => + theme.sidebar.spacing.offsetLeft + depth * theme.sidebar.spacing.offsetNesting}px; + padding: ${({ theme }) => theme.sidebar.spacing.paddingVertical}px + ${({ theme }) => theme.sidebar.spacing.paddingHorizontal}px; + + padding-left: ${ + ({ theme }) => + theme.sidebar.spacing.paddingHorizontal + theme.sidebar.spacing.unit * 1.5 /* 1 chevron width + 0.5 margin-right*/ + }px; + position: relative; + cursor: default; + font-family: ${({ theme }) => theme.sidebar.fontFamily}; + font-size: ${({ theme }) => theme.sidebar.fontSize}; + font-weight: ${({ theme }) => theme.typography.fontWeightBold}; + color: ${({ theme }) => theme.sidebar.separatorLabelColor}; + + &:empty { + padding: 0.1em 0; + } +`; + +const MenuLabel = styled.span` + width: 100%; +`; + +const ArrowWrapper = styled.div` + margin-right: 5px; +`; + +const StyledDrilldownMenuItem = styled.span` + display: inline-flex; + align-items: center; + color: ${({ theme }) => theme.sidebar.textColor}; + font-size: ${({ theme }) => theme.sidebar.fontSize}; + font-weight: ${({ theme }) => theme.typography.fontWeightBold}; +`; + +const DrilldownMenuIcon = styled.img` + width: ${({ theme }) => theme.sidebar.spacing.unit * 4}px; + height: ${({ theme }) => theme.sidebar.spacing.unit * 4}px; + margin-right: ${({ theme }) => theme.sidebar.spacing.unit}px; + border-radius: 50%; + flex-shrink: 0; + overflow: hidden; +`; + +const DrilldownMenuSublabel = styled.span` + display: block; + margin-top: 2px; + color: ${({ theme }) => theme.sidebar.textColorSecondary}; + font-size: 0.85rem; + font-weight: ${({ theme }) => theme.typography.fontWeightRegular}; +`; + +// const StyledOperationBadge = styled(OperationBadge)` +// flex-shrink: 0; +// margin-top: 0; +// `; + +function DrilldownMenuItem(props: { icon?: string | null; label?: string | null; sublabel?: string | null }) { + const { icon, label, sublabel } = props; + return ( + + {icon && } + + {label} + {sublabel && {sublabel}} + + + ); +} diff --git a/_override/NavBar.tsx b/_override/NavBar.tsx new file mode 100644 index 00000000..e223d777 --- /dev/null +++ b/_override/NavBar.tsx @@ -0,0 +1,190 @@ +import * as React from 'react'; +import styled from 'styled-components'; + +import { Flex, Link, NavBarProps, SearchBox } from '@redocly/developer-portal/ui'; + +/** + * Custom Navbar. The implementation below is almost identical to our default Navbar + */ +export default function CustomNavBar(props: NavBarProps) { + // you can use items values from props, it comes from siteConfig.yaml + // but you can also import it from a separate yaml or json file + const { items, logo, href, altText } = props; + + const [isMobileMenuOpened, setMobileMenuOpened] = React.useState(false); + const toggleMobileMenu = () => setMobileMenuOpened(!isMobileMenuOpened); + const hideMobileMenu = () => setMobileMenuOpened(false); + + + const navItems = items + .filter(item => item.type !== 'search') + .map((item, index) => { + return ( + + {item.label} + + ); + }); + + return ( + + + + + + + {navItems} + + + + + + + + + {navItems} + + + + ); +} + +// very important for NavWrapper to be a "nav" HTML tag +export const NavWrapper = styled.nav` + display: flex; + color: ${({ theme }) => theme.colors.navbar.contrastText}; + align-items: center; + justify-content: space-between; + flex-shrink: 0; + + background: ${({ theme }) => `linear-gradient( -63.43000000000001deg, + ${theme.colors.navbar.main} 15%, + ${theme.colors.navbar.gradient} 85%)`}; + + font-size: 1rem; + position: sticky; + top: 0; + z-index: 200; + padding: 1.125em 2.75em; + font-family: ${({ theme }) => theme.typography.headings.fontFamily}; + + @media only screen and (max-width: ${({ theme }) => theme.breakpoints.medium}) { + padding: 1.25em; + } + + @media only screen and (min-width: ${({ theme }) => theme.breakpoints.medium}) and (max-width: ${({ theme }) => + theme.breakpoints.large}) { + font-size: 0.875rem; + } +`; + +const NavItems = styled.ul` + display: none; + margin: 0 0 0 40px; + padding: 0; + align-items: center; + justify-content: start; + & li { + list-style: none; + margin-right: 20px; + & a { + color: #ffffff; + text-decoration: none; + } + } + @media only screen and (min-width: ${({ theme }) => theme.breakpoints.medium}) { + display: flex; + } +`; + +const NavItem = styled.li` + padding: 10px 0; +`; + +export const MobileMenu = styled.ul<{ isShown: boolean }>` + background: ${props => props.theme.colors.primary.main}; + list-style: none; + padding: 50px 40px; + margin: 0; + position: absolute; + border-top: 1px solid transparent; + z-index: 100; + color: ${props => props.theme.colors.primary.contrastText}; + top: 0; + right: 0; + left: 0; + bottom: 0; + font-size: 1.1875rem; + box-shadow: 0px 10px 100px 0px rgba(35, 35, 35, 0.1); + text-align: left; + display: none; + @media only screen and (max-width: ${({ theme }) => theme.breakpoints.medium}) { + position: fixed; + display: ${props => (props.isShown ? 'flex' : 'none')}; + flex-direction: column; + overflow-y: auto; + } + & li { + list-style: none; + margin-right: 20px; + & a { + color: #ffffff; + text-decoration: none; + } + } +`; + +export const NavControls = styled.div` + padding: 10px; + display: flex; + align-items: center; + flex: 1; + justify-content: flex-end; + @media only screen and (min-width: ${({ theme }) => theme.breakpoints.medium}) { + display: none; + } +`; + +export const MobileMenuIcon = styled.span` + width: 1.25em; + height: 1.25em; + display: inline-block; + background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' version='1.1' x='0' y='0' viewBox='0 0 396.7 396.7' xml:space='preserve'%3E%3Cpath fill='white' d='M17 87.8h362.7c9.4 0 17-7.6 17-17s-7.6-17-17-17H17c-9.3 0-17 7.7-17 17C0 80.2 7.7 87.8 17 87.8zM17 215.3h362.7c9.4 0 17-7.6 17-17s-7.6-17-17-17H17c-9.3 0-17 7.7-17 17S7.7 215.3 17 215.3zM17 342.8h362.7c9.4 0 17-7.6 17-17s-7.6-17-17-17H17c-9.3 0-17 7.7-17 17S7.7 342.8 17 342.8z'/%3E%3C/svg%3E"); + cursor: pointer; + @media only screen and (min-width: ${({ theme }) => theme.breakpoints.medium}) { + display: none; + } +`; + +export const CloseIcon = styled.i` + cursor: pointer; + position: absolute; + right: 20px; + top: 25px; + width: 15px; + height: 15px; + background-repeat: no-repeat; + background-size: 15px 15px; + background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' version='1.1' viewBox='0 0 15.6 15.6' enable-background='new 0 0 15.642 15.642'%3E%3Cpath fill-rule='evenodd' fill='white' d='M8.9 7.8l6.5-6.5c0.3-0.3 0.3-0.8 0-1.1 -0.3-0.3-0.8-0.3-1.1 0L7.8 6.8 1.3 0.2c-0.3-0.3-0.8-0.3-1.1 0 -0.3 0.3-0.3 0.8 0 1.1l6.5 6.5L0.2 14.4c-0.3 0.3-0.3 0.8 0 1.1 0.1 0.1 0.3 0.2 0.5 0.2s0.4-0.1 0.5-0.2l6.5-6.5 6.5 6.5c0.1 0.1 0.3 0.2 0.5 0.2 0.2 0 0.4-0.1 0.5-0.2 0.3-0.3 0.3-0.8 0-1.1L8.9 7.8z'/%3E%3C/svg%3E"); +`; + +export const Logo = styled.img` + cursor: pointer; + width: auto; + height: ${({ theme }) => theme.logo.height}; + max-width: ${({ theme }) => theme.logo.maxWidth}; + max-height: ${({ theme }) => theme.logo.maxHeight}; + + margin: ${({ theme }) => theme.logo.margin}; +`; + +export const LogoLink = styled(Link)` + display: inline-block; + margin-right: 2.75em; +`; diff --git a/_override/SearchInput.tsx b/_override/SearchInput.tsx new file mode 100644 index 00000000..2341b828 --- /dev/null +++ b/_override/SearchInput.tsx @@ -0,0 +1,56 @@ +import * as React from 'react'; + +import { + SearchInputProps, + SearchIcon, + SearchClearIcon, + SearchLoadingIcon, + SearchInputField, + SearchInputWrap, +} from '@redocly/developer-portal/ui'; + +/** + * Custom Search Input. The implementation below is almost identical to our default SearchInput. + */ +export default function CustomSearchInput(props: SearchInputProps) { + const { query, onChange, onToggleSearchResults, onKeyDown, onClear, loading } = props; + + const inputRef = React.useRef(null); + + const [isFocused, setIsFocused] = React.useState(false); + + React.useEffect(() => { + if (isFocused && query.length > 0) { + onToggleSearchResults(true); + } else { + onToggleSearchResults(false); + } + }, [isFocused, query]); + + return ( + + setIsFocused(true)} + onBlur={() => setIsFocused(false)} + onKeyDown={onKeyDown} + /> + {isFocused ? ( + loading ? ( + + ) : ( + + ) + ) : ( + inputRef.current && inputRef.current.focus()} /> + )} + + ); +} diff --git a/_override/SearchResults.tsx b/_override/SearchResults.tsx new file mode 100644 index 00000000..f8b28efa --- /dev/null +++ b/_override/SearchResults.tsx @@ -0,0 +1,105 @@ +import * as React from 'react'; +import styled from 'styled-components'; + +import { SearchResultItem, SearchResultsWrap, SearchResultsProps } from '@redocly/developer-portal/ui'; + +const MAX_ITEMS_PER_GROUP = 5; + +/** + * Custom User Search results. The implementation below is similar to our default search results but + * implements simple grouping by URL + */ + +export default function CustomSearchResults(props: SearchResultsProps) { + const { show, results, indexError, activeItemIdx, loading, query } = props; + + function isApiResult(item) { + return !!item.httpVerb && item.link.startsWith('/openapi'); // this is example + } + + const apiResults = { + title: 'API Documentation', + results: results.filter(isApiResult).slice(0, MAX_ITEMS_PER_GROUP), + }; + + const otherResults = { + title: 'Other Results', + results: results.filter(item => !isApiResult(item)).slice(0, MAX_ITEMS_PER_GROUP), + }; + + let currentPathname = typeof location !== 'undefined' ? location.pathname : '/'; + + // order results differently based on current page + const searchGroups = + currentPathname && currentPathname.startsWith('/openapi') ? [apiResults, otherResults] : [otherResults, apiResults]; + + return ( + + {indexError && process.env.NODE_ENV === 'development' && ( + + Failed to load search index. Search index is not working in develop.
+ Run yarn build to build the search index first (requires license key). +
+ )} + {results.length === 0 && !loading && Nothing Found } + + + {/* our default implementation iterates over the results directly */} + {/* + {results.map((item, idx) => ( + + ))} + */} + + {searchGroups.map((group, index) => { + return group.results.length ? ( + + {group.title} + {group.results.map((item, idx) => ( +
+ +
+ ))} +
+ ) : null; + })} + +
+ ); +} + +// to support keyboard navigation +const countIndex = (index, idx, searchGroups) => { + if (index === 0) { + return idx; + } else if (index === 1) { + return searchGroups[0].results.length + idx; + } +}; + +const Message = styled.div` + text-align: center; + color: ${props => props.theme.colors.primary.main}; + padding: 1.5em; + @media only screen and (max-width: ${({ theme }) => theme.breakpoints.medium}) { + padding: 0.75em; + } + color: #212129; +`; + +const SearchCatTitle = styled.div` + color: #919194; + padding: 16px 24px; + text-transform: uppercase; + font-size: 14px; +`; \ No newline at end of file diff --git a/_override/layouts/Markdown.tsx b/_override/layouts/Markdown.tsx new file mode 100644 index 00000000..33aef68a --- /dev/null +++ b/_override/layouts/Markdown.tsx @@ -0,0 +1,68 @@ +import * as React from 'react'; +import { MarkdownLayout as OriginalMarkdownLayout, MarkdownLayoutProps } from '@redocly/developer-portal/ui'; +import styled from 'styled-components'; + +/** + * Layout for markdown content. The implementation below modifies layout based on the location.pathname. + */ + +export default function CustomMarkdownLayout(props: MarkdownLayoutProps) { + const { withToc, lastModifiedAgo, Toc, children, location } = props; + + if (location.pathname.endsWith('/blog/')) { + // render modified layout if pathname starts with /blog + + // You get markdown page content in {children}. + // The code below is showing our default Markdown layout. + // But it can be replaced completely. + + return ( + + + {lastModifiedAgo && ( + + Last updated {lastModifiedAgo} + + )} + {children} + + + + ); + } + + // render default layout otherwise + return ; +} + +const PageWrapper = styled.div` + display: flex; + flex: 1; + width: 100%; +`; + +const PageInfo = styled.div` + display: flex; + align-items: center; + font-size: 0.8125rem; + margin-bottom: 1.5em; +`; + +const PageInfoText = styled.span` + color: ${props => props.theme.colors.text.primary}; + font-weight: ${props => props.theme.typography.fontWeightRegular}; + font-family: ${({ theme }) => theme.typography.fontFamily}; +`; + +const ContentWrapper = styled.section<{ withToc: boolean }>` + width: 90%; + margin: 25px auto; + @media only screen and (min-width: ${({ theme }) => theme.breakpoints.large}) { + max-width: 910px; + } + @media only screen and (min-width: ${({ theme }) => theme.breakpoints.medium}) { + width: ${({ withToc, theme }) => (withToc ? `calc(90% - ${theme.tocPanel.width})` : '90%')}; + padding-top: 40px; + padding-bottom: 40px; + } +`; diff --git a/_override/layouts/sidebar.tsx b/_override/layouts/sidebar.tsx new file mode 100644 index 00000000..2f0d8f41 --- /dev/null +++ b/_override/layouts/sidebar.tsx @@ -0,0 +1,38 @@ +import * as React from 'react'; +import { SidebarLayout as OriginalSidebarLayout, SidebarProps } from '@redocly/developer-portal/ui'; + +import styled, { createGlobalStyle } from 'styled-components'; + +/** + * Layout with sidebar. The implementation below wraps original sidebar layout adding paper-like UI. + */ + +export default function CustomSidebarLayout(props: SidebarProps) { + return ( + + + + {props.children} {/* page contents in props.children */} + + + ); +} + +const BodyBg = createGlobalStyle` + body { + background-color: #eeeeee; + } +`; + +const SidebarWrapper = styled.div` + width: 90%; + max-width: 1400px; + margin: 20px auto; + padding: 10px 0px; + border-radius: 10px; + background-color: white; + box-shadow: 0 1px 3px rgba(0, 0, 0, 0.12), 0 1px 2px rgba(0, 0, 0, 0.24); + @media only screen and (min-width: ${({ theme }) => theme.breakpoints.medium}) { + width: 100%; + } +`; \ No newline at end of file diff --git a/package.json b/package.json index a59676fa..12bb5c76 100644 --- a/package.json +++ b/package.json @@ -10,6 +10,6 @@ "clean": "redocly-portal clean" }, "dependencies": { - "@redocly/developer-portal": "1.1.0-beta.101" + "@redocly/developer-portal": "1.1.0-beta.104" } } diff --git a/yarn.lock b/yarn.lock index 0e966ef4..d7bd505d 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1710,17 +1710,17 @@ require-from-string "^2.0.2" uri-js "^4.2.2" -"@redocly/developer-portal@1.1.0-beta.101": - version "1.1.0-beta.101" - resolved "https://registry.yarnpkg.com/@redocly/developer-portal/-/developer-portal-1.1.0-beta.101.tgz#db84d816bc9e1aab59968019719acebcdd554079" - integrity sha512-GMTy4L97kHpN+APU7zqrLOMf12Lqt+CtUPvrmtaXWqr0iLT35heH/k/miu4Bmeb9Vp9lRBB6dP2Xk2xhsKnGlA== +"@redocly/developer-portal@1.1.0-beta.104": + version "1.1.0-beta.104" + resolved "https://registry.yarnpkg.com/@redocly/developer-portal/-/developer-portal-1.1.0-beta.104.tgz#256f7aa330a533ce9717108ab2129bedf5997ae8" + integrity sha512-tGJo6nKreoafpTyGycT7PsVySwTV1QgWuRlAZ4FqPevzMRj08NlVz4ndxcM5rYQ0jSMq5iELBXymEq3WWsihWg== dependencies: "@mdx-js/mdx" "0.19.0" "@mdx-js/tag" "0.20.3" "@redocly/gatsby-plugin-manifest" "3.3.2" "@redocly/gatsby-remark-images" "4.2.0" - "@redocly/openapi-core" "1.0.0-beta.102" - "@redocly/reference-docs" "2.25.1" + "@redocly/openapi-core" "1.0.0-beta.103" + "@redocly/reference-docs" "2.26.3" babel-plugin-react-html-attrs "^3.0.5" babel-plugin-styled-components "^1.12.0" buffer "^6.0.3" @@ -1863,10 +1863,10 @@ unist-util-select "^1.5.0" unist-util-visit-parents "^2.1.2" -"@redocly/openapi-core@1.0.0-beta.102": - version "1.0.0-beta.102" - resolved "https://registry.yarnpkg.com/@redocly/openapi-core/-/openapi-core-1.0.0-beta.102.tgz#e1cd049979f05812c594063fec71e618201319c4" - integrity sha512-3Fr3fg+9VEF4+4uoyvOOk+9ipmX2GYhlb18uZbpC4v3cUgGpkTRGZM2Qetfah7Tgx2LgqLuw8A1icDD6Zed2Gw== +"@redocly/openapi-core@1.0.0-beta.103": + version "1.0.0-beta.103" + resolved "https://registry.yarnpkg.com/@redocly/openapi-core/-/openapi-core-1.0.0-beta.103.tgz#fff3fd5071d718cff6f135fe9ca3d0f154551302" + integrity sha512-O9ln5sQycdZsHsNbe3eZzDzi/h5mC94mCSZGrx2NbMXJNOqXOuNtG5si5Eamx/1BZgQLL+KhKCVea3QvWyjEcQ== dependencies: "@redocly/ajv" "^8.6.4" "@types/node" "^14.11.8" @@ -1895,15 +1895,14 @@ pluralize "^8.0.0" yaml-ast-parser "0.0.43" -"@redocly/reference-docs@2.25.1": - version "2.25.1" - resolved "https://registry.yarnpkg.com/@redocly/reference-docs/-/reference-docs-2.25.1.tgz#ca27a501c05bb217acc889c05d361a09faa96ccd" - integrity sha512-D0DB7zj/O0LKYKVmqwZYVc5p7Q+wehaD4nWX2A45U75W85cQiUuKal5Mp+Wk0COk+suMvyLnd3NeYK13RWd6DQ== +"@redocly/reference-docs@2.26.3": + version "2.26.3" + resolved "https://registry.yarnpkg.com/@redocly/reference-docs/-/reference-docs-2.26.3.tgz#a94b9afbcf6c7b859440fa3cf4a3a3ee6dcff572" + integrity sha512-eCJGB4yV2SyPbRavQi0x05/m2M+Znp7zNBIESoFHtKDrCSqzattuHG3SSTRdlw49yV7P/QsnfGm+9oIaFTdxdQ== dependencies: "@redocly/openapi-core" "1.0.0-beta.97" "@redocly/vscode-json-languageservice" "3.4.9" "@wojtekmaj/enzyme-adapter-react-17" "^0.6.2" - classnames "^2.2.6" codemirror "^5.65.0" decko "^1.2.0" deepmerge "^4.2.2" @@ -1926,7 +1925,6 @@ perfect-scrollbar "^1.5.5" polished "^3.6.5" prismjs "^1.22.0" - prop-types "^15.7.2" query-string "^6.13.6" react-codemirror2-react-17 "1.0.0" react-tabs "^3.1.1" @@ -4189,7 +4187,7 @@ class-utils@^0.3.5: isobject "^3.0.0" static-extend "^0.1.1" -classnames@^2.1.2, classnames@^2.2.6: +classnames@^2.1.2: version "2.3.1" resolved "https://registry.yarnpkg.com/classnames/-/classnames-2.3.1.tgz#dfcfa3891e306ec1dad105d0e88f4417b8535e8e" integrity sha512-OlQdbZ7gLfGarSqxesMesDa5uz7KFbID8Kpq/SxIoNGDqY8lSYs0D+hhtBXhcdB3rcbXArFr7vlHheLk1voeNA==