Mirror: The highly customizable and versatile GraphQL client with which you add on features like normalized caching as you grow.

Update docs site design after review (#595)

* Update typography colours

All headings are now #444444 (heading)
All sidebar/legend items are now #444444 (passive)

* Fix jumpy legend position

* Fix stripes and sidebar layout

* Reduce font-size on mobile to 15px effectively

* Add sidebar collapsing sections and active styling

* Update sidebar size and padding

* Fix links in mdx using react-router-dom Link

* Fix Loading page design

* Add basic implementation for <ScrollToTop />

* Fix internal links on index pages

This will need further fixes in the plugin

* Fix internal links on /docs/

* Update react-static-plugin-md-pages to fix lost state

* Add usePrefetch hook to home screen to increase load consistency

* Upgrade react-static-plugin-md-pages to fix page update

* Add missing suspense rethrow to custom catch code

* update <Loading /> so that it isn't affected by throws/suspense

* remove duplicate <Article /> parts

* WIP: enable the 404 page on the built app

* Upgrade react-static-plugin-md-pages to remove page data requirement

* Fix path resolution for internal links properly

* Fix homepage links in staging and add link to logo

* Fix local relative internal links on same level

* fix markdown links from other pages

* Fix several hash anchor links

Co-authored-by: Will Golledge <will.golledge@formidable.com>
Co-authored-by: wgolledge <wiggiumg@gmail.com>

authored by kitten.sh

Will Golledge
wgolledge
and committed by
GitHub
468f9445 f8b60fce

+301 -303
+1 -1
docs/advanced/README.md
··· 7 7 8 8 In this chapter we'll dive into various topics of "advanced" `urql` usage. This is admittedly a 9 9 catch-all chapter of various use-cases that can only be covered after [the "Concepts" 10 - chapter.](../coconcepts/README.md) 10 + chapter.](../concepts/README.md) 11 11 12 12 - **Subscriptions** covers how to use `useSubscription` and how to set up GraphQL subscriptions with 13 13 `urql`.
+1 -1
docs/advanced/subscriptions.md
··· 75 75 ## React & Preact 76 76 77 77 The `useSubscription` hooks comes with a similar API to `useQuery`, which [we've learned about in 78 - the "Queries" page in the "Basics" section.](../basics/querying-data.md) 78 + the "Queries" page in the "Basics" section.](../basics/queries.md) 79 79 80 80 Its usage is extremely similar in that it accepts options, which may contain `query` and 81 81 `variables`. However, it also accepts a second argument, which is a reducer function, similar to
+1 -1
docs/graphcache/computed-queries.md
··· 35 35 would be the full `Todo` object. 36 36 - `arguments` – The arguments used in this field. 37 37 - `cache` – This is the normalized cache. The cache provides us with `resolve`, `readQuery` and `readFragment` methods, 38 - read more about this [below](#cache.resolve). 38 + read more about this [below](#resolve). 39 39 - `info` – This contains the fragments used in the query and the field arguments in the query. 40 40 41 41 ## Cache parameter
+15
packages/react-urql/core/yarn.lock
··· 1 + # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. 2 + # yarn lockfile v1 3 + 4 + 5 + "@urql/core@^1.7.0": 6 + version "1.9.2" 7 + resolved "https://registry.yarnpkg.com/@urql/core/-/core-1.9.2.tgz#bc2880a279dd5ada26527063c7a173fda26abb58" 8 + integrity sha512-0eitjW/HlUAkMTwiWFQyQkcmwAlnWlscH3/AKU1Y5MJUzzehAkOffHFQ9eD5st/0TlKSvehbz/eUAHDq/CnX8w== 9 + dependencies: 10 + wonka "^4.0.7" 11 + 12 + wonka@^4.0.7: 13 + version "4.0.7" 14 + resolved "https://registry.yarnpkg.com/wonka/-/wonka-4.0.7.tgz#b4934685bd2449367bd72ce7770bfe3e6cc8a68b" 15 + integrity sha512-Uhyl2cgWCUksYtU0Jt8MSzKUqK4BVUrewWxnn1YlKL3Zco4sDcCUDkbgH0i762HJs1rtsq03cfzsCWxJKaDgVg==
+1 -1
packages/site/package.json
··· 48 48 "react-router-ga": "^1.0.0", 49 49 "react-scroll": "^1.7.15", 50 50 "react-static": "^7.2.3", 51 - "react-static-plugin-md-pages": "^0.1.3", 51 + "react-static-plugin-md-pages": "^0.1.7", 52 52 "styled-components": "^5.0.1" 53 53 }, 54 54 "devDependencies": {
-1
packages/site/src/app.js
··· 9 9 import * as theme from './styles/theme'; 10 10 import Analytics from './google-analytics'; 11 11 import { Loading } from './components/loading'; 12 - // TODO: import NotFound from './screens/404'; 13 12 14 13 const App = () => { 15 14 return (
+13
packages/site/src/assets/chevron.js
··· 1 + import React from 'react'; 2 + 3 + const SvgChevron = props => ( 4 + <svg viewBox="0 0 12 10" {...props}> 5 + <path 6 + d="M1.41 1L6 5.33 10.59 1 12 2.34 6 8 0 2.34z" 7 + fill="currentColor" 8 + fillRule="nonzero" 9 + /> 10 + </svg> 11 + ); 12 + 13 + export default SvgChevron;
+8
packages/site/src/assets/chevron.svg
··· 1 + <?xml version="1.0" encoding="UTF-8"?> 2 + <svg viewBox="0 0 12 10" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"> 3 + <g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd"> 4 + <g id="chevron-down" transform="translate(0.000000, 1.000000)" fill="currentColor" fill-rule="nonzero"> 5 + <polygon id="Path" points="1.41 0 6 4.33018868 10.59 0 12 1.33962264 6 7 0 1.33962264"></polygon> 6 + </g> 7 + </g> 8 + </svg>
+22 -24
packages/site/src/components/loading.js
··· 1 1 import React from 'react'; 2 2 import styled, { keyframes } from 'styled-components'; 3 - import { Container as DocsContainer } from '../screens/docs'; 4 - import Header from '../screens/docs/header'; 3 + import Docs from '../screens/docs'; 5 4 6 5 const Container = styled.div` 7 6 height: 100vh; 8 7 width: 100%; 9 8 `; 9 + 10 10 const Loader = styled.div` 11 11 position: relative; 12 12 margin: 0 auto; 13 13 width: ${p => p.theme.spacing.xl}; 14 14 top: calc(50% - ${p => p.theme.spacing.xl}); 15 + 15 16 &:before { 16 17 content: ''; 17 18 display: block; ··· 61 62 stroke-linecap: round; 62 63 `; 63 64 64 - export const Loading = () => { 65 - return ( 66 - <DocsContainer> 67 - <Container> 68 - <Header /> 69 - <Loader> 70 - <Svg className="circular" viewBox="25 25 50 50"> 71 - <Circle 72 - className="path" 73 - cx="50" 74 - cy="50" 75 - r="20" 76 - fill="none" 77 - strokeWidth="2" 78 - strokeMiterlimit="10" 79 - /> 80 - </Svg> 81 - </Loader> 82 - </Container> 83 - </DocsContainer> 84 - ); 85 - }; 65 + export const Loading = () => ( 66 + <Docs isLoading> 67 + <Container> 68 + <Loader> 69 + <Svg className="circular" viewBox="25 25 50 50"> 70 + <Circle 71 + className="path" 72 + cx="50" 73 + cy="50" 74 + r="20" 75 + fill="none" 76 + strokeWidth="2" 77 + strokeMiterlimit="10" 78 + /> 79 + </Svg> 80 + </Loader> 81 + </Container> 82 + </Docs> 83 + );
+22 -1
packages/site/src/components/mdx.js
··· 1 1 import React from 'react'; 2 + import * as path from 'path'; 2 3 import styled, { css } from 'styled-components'; 3 4 import { MDXProvider } from '@mdx-js/react'; 4 - 5 + import { useLocation, Link } from 'react-router-dom'; 6 + import { useMarkdownPage } from 'react-static-plugin-md-pages'; 5 7 import Highlight, { Prism } from 'prism-react-renderer'; 6 8 import nightOwlLight from 'prism-react-renderer/themes/nightOwlLight'; 9 + 10 + import { relative } from './sidebar'; 7 11 8 12 const getLanguage = className => { 9 13 const res = className.match(/language-(\w+)/); ··· 206 210 </TableOverflow> 207 211 ); 208 212 213 + const MdLink = ({ href, children }) => { 214 + const location = useLocation(); 215 + const currentPage = useMarkdownPage(); 216 + 217 + if (!/^\w+:/.test(href) && !href.startsWith('#')) { 218 + const hasTrailingSlash = location.pathname.endsWith('/'); 219 + const from = !hasTrailingSlash ? currentPage.path + '/' : currentPage.path; 220 + const to = hasTrailingSlash 221 + ? path.join(path.dirname(currentPage.originalPath), href) 222 + : path.join(currentPage.path, href); 223 + return <Link to={relative(from, to)}>{children}</Link>; 224 + } 225 + 226 + return <a href={href}>{children}</a>; 227 + }; 228 + 209 229 const components = { 210 230 pre: Pre, 211 231 img: Image, ··· 215 235 table: TableWithOverflow, 216 236 th: TableHeader, 217 237 td: TableCell, 238 + a: MdLink, 218 239 }; 219 240 220 241 export const MDXComponents = ({ children }) => (
+47 -10
packages/site/src/components/navigation.js
··· 1 1 import styled from 'styled-components'; 2 - import { Link } from 'react-router-dom'; 2 + import { NavLink } from 'react-router-dom'; 3 + 4 + import ChevronIcon from '../assets/chevron'; 3 5 4 6 export const SidebarContainer = styled.div` 5 7 display: ${p => (p.hidden ? 'none' : 'block')}; ··· 9 11 display: block; 10 12 position: relative; 11 13 width: ${p => p.theme.layout.sidebar}; 14 + margin-left: calc(2 * ${p => p.theme.layout.stripes}); 12 15 } 13 16 `; 14 17 ··· 38 41 line-height: ${p => p.theme.lineHeights.body}; 39 42 font-size: ${p => p.theme.fontSizes.small}; 40 43 41 - padding: ${p => p.theme.spacing.md}; 42 - padding-right: ${p => p.theme.spacing.sm}; 43 - 44 + padding: ${p => p.theme.spacing.sm} ${p => p.theme.spacing.md}; 44 45 background-color: ${p => p.theme.colors.bg}; 45 46 border-right: 1px solid ${p => p.theme.colors.border}; 46 47 border-top: 1px solid ${p => p.theme.colors.border}; ··· 48 49 @media ${({ theme }) => theme.media.sm} { 49 50 border: none; 50 51 background: none; 51 - padding-top: ${p => p.theme.spacing.lg}; 52 + padding-top: ${p => p.theme.spacing.md}; 52 53 width: ${p => p.theme.layout.sidebar}; 53 54 } 54 55 `; 55 56 56 - export const SidebarNavItem = styled(Link)` 57 + export const SidebarNavItem = styled(NavLink).attrs(() => ({ 58 + activeClassName: 'active', 59 + }))` 57 60 display: block; 58 61 margin: ${p => p.theme.spacing.xs} 0; 59 - color: ${p => p.theme.colors.accent}; 62 + color: ${p => p.theme.colors.text}; 60 63 font-weight: ${p => p.theme.fontWeights.heading}; 61 64 text-decoration: none; 62 65 width: 100%; 66 + 67 + &:hover { 68 + color: ${p => p.theme.colors.accent}; 69 + } 70 + 71 + &.active { 72 + color: ${p => p.theme.colors.accent}; 73 + } 74 + `; 75 + 76 + export const ChevronItem = styled(ChevronIcon)` 77 + display: inline-block; 78 + color: inherit; 79 + vertical-align: baseline; 80 + margin-top: 0.08em; 81 + margin-left: 0.3em; 82 + padding: 0.08em; 83 + width: 1em; 84 + height: 1em; 85 + 86 + position: relative; 87 + top: 0.16em; 88 + 89 + ${SidebarNavItem}.active & { 90 + transform: rotate(180deg); 91 + } 63 92 `; 64 93 65 94 export const SidebarNavSubItemWrapper = styled.div` ··· 67 96 margin-bottom: ${p => p.theme.spacing.xs}; 68 97 `; 69 98 70 - export const SidebarNavSubItem = styled(Link)` 99 + export const SidebarNavSubItem = styled(NavLink).attrs(() => ({}))` 71 100 display: block; 72 - color: ${p => p.theme.colors.heading}; 101 + color: ${p => p.theme.colors.passive}; 73 102 font-weight: ${p => p.theme.fontWeights.body}; 74 103 text-decoration: none; 75 104 margin-top: ${p => p.theme.spacing.xs}; 76 - opacity: 0.7; 77 105 78 106 &:first-child { 79 107 margin-top: 0; 108 + } 109 + 110 + &:hover { 111 + color: ${p => p.theme.colors.accent}; 112 + } 113 + 114 + &.active { 115 + color: ${p => p.theme.colors.accent}; 116 + font-weight: ${p => p.theme.fontWeights.heading}; 80 117 } 81 118 `;
+23
packages/site/src/components/scroll-to-top.js
··· 1 + import React, { useEffect, useRef } from 'react'; 2 + import { useLocation } from 'react-router-dom'; 3 + import { useMarkdownPage } from 'react-static-plugin-md-pages'; 4 + 5 + export const ScrollToTop = () => { 6 + const inputRef = useRef(null); 7 + const location = useLocation(); 8 + const md = useMarkdownPage(); 9 + 10 + const hash = 11 + location.hash || 12 + (location.pathname && location.pathname.match(/#[a-z|-]+/)); 13 + 14 + useEffect(() => { 15 + if (hash && md) { 16 + inputRef.current.click(); 17 + } else { 18 + window.scrollTo(0, 0); 19 + } 20 + }, [hash, md]); 21 + 22 + return <a href={hash} ref={inputRef} />; 23 + };
+61 -27
packages/site/src/components/sidebar.js
··· 1 + /* eslint-disable react-hooks/rules-of-hooks */ 2 + 1 3 import React, { Fragment, useMemo } from 'react'; 2 4 import styled from 'styled-components'; 3 - import { useLocation } from 'react-router-dom'; 5 + import { useBasepath } from 'react-static'; 6 + import { Link, useLocation } from 'react-router-dom'; 4 7 import * as path from 'path'; 5 8 6 9 import { useMarkdownTree, useMarkdownPage } from 'react-static-plugin-md-pages'; ··· 12 15 SidebarContainer, 13 16 SidebarWrapper, 14 17 SideBarStripes, 18 + ChevronItem, 15 19 } from './navigation'; 16 20 17 21 import logoSidebar from '../assets/sidebar-badge.svg'; 18 22 23 + const HeroLogoLink = styled(Link)` 24 + display: flex; 25 + flex-direction: row; 26 + justify-content: center; 27 + margin-bottom: ${p => p.theme.spacing.sm}; 28 + align-self: center; 29 + `; 30 + 19 31 const HeroLogo = styled.img.attrs(() => ({ 20 32 src: logoSidebar, 21 33 alt: 'urql', 22 34 }))` 23 35 display: none; 24 36 width: ${p => p.theme.layout.logo}; 25 - margin-bottom: ${p => p.theme.spacing.sm}; 26 - align-self: center; 27 37 28 38 @media ${p => p.theme.media.sm} { 29 39 display: block; ··· 35 45 flex-direction: column; 36 46 padding-top: ${p => p.theme.spacing.xs}; 37 47 padding-bottom: ${p => p.theme.spacing.lg}; 38 - padding-left: ${p => p.theme.spacing.sm}; 39 48 `; 40 49 41 - const relative = (from, to) => { 50 + export const relative = (from, to) => { 42 51 if (!from || !to) return null; 43 - let pathname = path.relative(path.dirname(from), to); 52 + let [toPath, hash] = to.split('#'); 53 + let pathname = path.relative(path.dirname(from), toPath); 44 54 if (!pathname) 45 - pathname = path.join(path.relative(from, to), path.basename(to)); 46 - if (from.endsWith('/')) pathname = '../' + pathname; 55 + pathname = path.join(path.relative(from, toPath), path.basename(toPath)); 56 + if (from.endsWith('/')) pathname = '../' + pathname + '/'; 57 + if (!pathname.endsWith('/')) pathname += '/'; 58 + if (hash) pathname += `#${hash}`; 47 59 return { pathname }; 48 60 }; 49 61 50 - const Sidebar = ({ sidebarOpen }) => { 62 + export const SidebarStyling = ({ children, sidebarOpen }) => { 63 + const basepath = useBasepath() || ''; 64 + const homepage = basepath ? `/${basepath}/` : '/'; 65 + 66 + return ( 67 + <> 68 + <SideBarStripes /> 69 + <SidebarContainer hidden={!sidebarOpen}> 70 + <SidebarWrapper> 71 + <HeroLogoLink to={homepage}> 72 + <HeroLogo /> 73 + </HeroLogoLink> 74 + <ContentWrapper>{children}</ContentWrapper> 75 + </SidebarWrapper> 76 + </SidebarContainer> 77 + </> 78 + ); 79 + }; 80 + 81 + const Sidebar = props => { 51 82 const location = useLocation(); 52 83 const currentPage = useMarkdownPage(); 53 84 const tree = useMarkdownTree(); 54 85 55 - const pathname = location.pathname.endsWith('/') 56 - ? currentPage.path + '/' 57 - : currentPage.path; 58 - 59 86 const sidebarItems = useMemo(() => { 60 - if (!currentPage || !tree || !tree.children) { 87 + if (!currentPage || !tree || !tree.children || !location) { 61 88 return null; 62 89 } 63 90 91 + const pathname = location.pathname.endsWith('/') 92 + ? currentPage.path + '/' 93 + : currentPage.path; 94 + 64 95 let children = tree.children; 65 96 if (tree.frontmatter && tree.originalPath) { 66 97 children = [{ ...tree, children: undefined }, ...children]; 67 98 } 68 99 69 100 return children.map(page => { 101 + const pageChildren = page.children || []; 102 + 103 + const isActive = pageChildren.length 104 + ? currentPage.path.startsWith(page.path) 105 + : currentPage.path === page.path; 106 + 70 107 return ( 71 108 <Fragment key={page.key}> 72 - <SidebarNavItem to={relative(pathname, page.path)}> 109 + <SidebarNavItem 110 + to={relative(pathname, page.path)} 111 + isActive={() => isActive} 112 + > 73 113 {page.frontmatter.title} 114 + {pageChildren.length ? <ChevronItem /> : null} 74 115 </SidebarNavItem> 75 116 76 - {page.children && page.children.length ? ( 117 + {pageChildren.length && isActive ? ( 77 118 <SidebarNavSubItemWrapper> 78 - {page.children.map(childPage => ( 119 + {pageChildren.map(childPage => ( 79 120 <SidebarNavSubItem 121 + isActive={() => childPage.path === currentPage.path} 80 122 to={relative(pathname, childPage.path)} 81 123 key={childPage.key} 82 124 > ··· 88 130 </Fragment> 89 131 ); 90 132 }); 91 - }, [currentPage, tree, pathname]); 133 + }, [currentPage, tree, location]); 92 134 93 - return ( 94 - <SidebarContainer hidden={!sidebarOpen}> 95 - <SideBarStripes /> 96 - <SidebarWrapper> 97 - <HeroLogo /> 98 - <ContentWrapper>{sidebarItems}</ContentWrapper> 99 - </SidebarWrapper> 100 - </SidebarContainer> 101 - ); 135 + return <SidebarStyling {...props}>{sidebarItems}</SidebarStyling>; 102 136 }; 103 137 104 138 export default Sidebar;
+1 -1
packages/site/src/screens/404/404.js
··· 1 1 import React from 'react'; 2 2 3 3 const NotFound = props => { 4 - return <h1>404! HELP I NEED DESIGNS</h1>; 4 + return <h1>404! That page does not exist :(</h1>; 5 5 }; 6 6 7 7 export default NotFound;
+7 -157
packages/site/src/screens/404/index.js
··· 1 - import React, { forwardRef } from 'react'; 2 - import styled from 'styled-components'; 3 - import PropTypes from 'prop-types'; 4 - import { withRouteData } from 'react-static'; 5 - import { Link } from 'react-router-dom'; 6 - 1 + import React from 'react'; 2 + import Docs from '../docs'; 7 3 import NotFoundPage from './404'; 8 - import Sidebar from '../../components/sidebar'; 9 - import constants from '../../constants'; 10 4 11 - import burger from '../../assets/burger.svg'; 12 - import logoFormidableDark from '../../assets/logo_formidable_dark.svg'; 13 - 14 - const Container = styled.div` 15 - display: flex; 16 - flex-direction: row; 17 - width: 100%; 18 - `; 19 - 20 - const Wrapper = styled.div` 21 - align-items: center; 22 - display: flex; 23 - flex-direction: row; 24 - height: 6rem; 25 - width: 100%; 26 - position: fixed; 27 - left: 19rem; 28 - background: white; 29 - z-index: 1; 30 - padding-right: 3rem; 31 - box-shadow: 0 5px 10px -5px lightgrey; 32 - 33 - @media (max-width: 768px) { 34 - box-shadow: 0 5px 10px -5px lightgrey; 35 - margin-left: 2.5rem; 36 - right: 0; 37 - width: calc(100% - 2rem); 38 - justify-content: flex-start; 39 - left: 0; 40 - } 41 - `; 42 - 43 - const HeaderLogo = styled.img` 44 - position: relative; 45 - right: 25rem; 46 - 47 - @media (max-width: 768px) { 48 - right: 7rem; 49 - padding-left: 2rem; 50 - } 51 - @media (max-width: 600px) { 52 - display: none; 53 - } 54 - `; 55 - 56 - const CollapsedMenu = styled.div` 57 - cursor: pointer; 58 - padding-left: 2.5rem; 59 - display: none; 60 - 61 - @media (max-width: 768px) { 62 - display: block; 63 - visibility: ${props => (props.overlay ? 'hidden' : 'visible')}; 64 - padding-left: 2.5rem; 65 - position: absolute; 66 - left: 0; 67 - } 68 - @media (max-width: 600px) { 69 - padding-left: 2.5rem; 70 - position: absolute; 71 - left: 0; 72 - } 73 - `; 74 - 75 - const DocsTitle = styled.h2` 76 - font-size: 3rem; 77 - top: 0.2rem; 78 - flex: auto; 79 - width: 100%; 80 - letter-spacing: 0.5rem; 81 - margin: 0; 82 - position: relative; 83 - left: 10rem; 84 - 85 - @media (max-width: 768px) { 86 - font-size: 3rem; 87 - left: 6.5rem; 88 - margin: 0; 89 - } 90 - @media (max-width: 600px) { 91 - left: 6.5rem; 92 - } 93 - `; 94 - 95 - // eslint-disable-next-line react/display-name 96 - const SideBarWithRef = forwardRef((props, ref) => { 5 + const NotFound = () => { 97 6 return ( 98 - <div ref={ref}> 99 - <Sidebar {...props} /> 100 - </div> 7 + <Docs isLoading> 8 + <NotFoundPage /> 9 + </Docs> 101 10 ); 102 - }); 103 - 104 - /* eslint-disable react/no-multi-comp */ 105 - class NotFound extends React.Component { 106 - constructor(props) { 107 - super(props); 108 - this.closeSidebar = this.closeSidebar.bind(this); 109 - this.state = { openSidebar: false }; 110 - this.sidebarRef = React.createRef(); 111 - } 112 - 113 - openSidebar() { 114 - this.setState({ openSidebar: true }); 115 - } 116 - 117 - closeSidebar() { 118 - this.setState({ openSidebar: false }); 119 - } 120 - 121 - render() { 122 - return ( 123 - <Container 124 - onClick={event => { 125 - return !this.sidebarRef.current.contains(event.target) && 126 - this.state.openSidebar 127 - ? this.closeSidebar() 128 - : null; 129 - }} 130 - > 131 - <Wrapper noPadding> 132 - <CollapsedMenu overlay={this.state.openSidebar}> 133 - <img src={burger} alt="Menu" onClick={() => this.openSidebar()} /> 134 - </CollapsedMenu> 135 - <DocsTitle> 136 - <Link to={'/'} style={{ color: '#3b3b3b' }}> 137 - {constants.docsTitle} 138 - </Link> 139 - </DocsTitle> 140 - <Link to={'https://formidable.com'}> 141 - <HeaderLogo src={logoFormidableDark} alt="Formidable Logo" /> 142 - </Link> 143 - </Wrapper> 144 - <SideBarWithRef 145 - overlay={this.state.openSidebar} 146 - closeSidebar={this.closeSidebar} 147 - ref={this.sidebarRef} 148 - /> 149 - <NotFoundPage /> 150 - </Container> 151 - ); 152 - } 153 - } 154 - 155 - NotFound.propTypes = { 156 - params: PropTypes.object, 157 11 }; 158 12 159 - NotFound.defaultProps = { 160 - params: null, 161 - }; 162 - 163 - export default withRouteData(NotFound); 13 + export default NotFound;
+20 -14
packages/site/src/screens/docs/article.js
··· 1 + /* eslint-disable react-hooks/rules-of-hooks */ 2 + 1 3 import React from 'react'; 2 4 import styled from 'styled-components'; 3 5 import { useMarkdownPage } from 'react-static-plugin-md-pages'; 6 + import { ScrollToTop } from '../../components/scroll-to-top'; 4 7 5 8 import { MDXComponents } from '../../components/mdx'; 6 9 ··· 9 12 }))` 10 13 flex: 1; 11 14 width: 100%; 12 - position: sticky; 13 15 display: flex; 14 16 flex-direction: row-reverse; 17 + align-items: flex-start; 15 18 `; 16 19 17 20 const Content = styled.article.attrs(() => ({ ··· 39 42 display: block; 40 43 position: sticky; 41 44 top: ${p => p.theme.layout.header}; 42 - max-height: 100vh; 43 45 width: 100%; 44 46 max-width: ${p => p.theme.layout.legend}; 45 - margin: 0 ${p => p.theme.spacing.md}; 46 - padding: ${p => p.theme.spacing.lg} 0; 47 + padding: ${p => p.theme.spacing.lg} ${p => p.theme.spacing.md}; 48 + margin: 0; 47 49 } 48 50 `; 49 51 ··· 66 68 > a { 67 69 font-size: ${p => p.theme.fontSizes.small}; 68 70 font-weight: ${p => p.theme.fontWeights.body}; 69 - color: ${p => p.theme.colors.heading}; 71 + color: ${p => p.theme.colors.passive}; 70 72 text-decoration: none; 71 - opacity: 0.7; 72 73 } 73 74 `; 74 75 75 76 const SectionList = () => { 76 77 const page = useMarkdownPage(); 77 - if (!page) return null; 78 + if (!page || !page.headings) return null; 78 79 79 80 const headings = page.headings.filter(x => x.depth > 1); 80 81 if (headings.length === 0) return null; ··· 93 94 ); 94 95 }; 95 96 96 - const Article = ({ children }) => ( 97 + export const ArticleStyling = ({ children, SectionList }) => ( 97 98 <Container> 98 - <Legend> 99 - <SectionList /> 100 - </Legend> 101 - <Content> 99 + <Legend>{SectionList && <SectionList />}</Legend> 100 + <Content>{children}</Content> 101 + </Container> 102 + ); 103 + 104 + const Article = ({ children }) => ( 105 + <> 106 + <ScrollToTop /> 107 + <ArticleStyling SectionList={SectionList}> 102 108 <MDXComponents>{children}</MDXComponents> 103 - </Content> 104 - </Container> 109 + </ArticleStyling> 110 + </> 105 111 ); 106 112 107 113 export default Article;
+2 -1
packages/site/src/screens/docs/header.js
··· 55 55 56 56 const Header = () => { 57 57 const basepath = useBasepath() || ''; 58 + const homepage = basepath ? `/${basepath}/` : '/'; 58 59 59 60 return ( 60 61 <Fixed> ··· 62 63 <BlockLink href="https://formidable.com/"> 63 64 <FormidableLogo /> 64 65 </BlockLink> 65 - <ProjectWording to={`/${basepath}/`}>urql</ProjectWording> 66 + <ProjectWording to={homepage}>urql</ProjectWording> 66 67 </Wrapper> 67 68 </Fixed> 68 69 );
+18 -21
packages/site/src/screens/docs/index.js
··· 1 1 import React, { useState } from 'react'; 2 2 import styled from 'styled-components'; 3 - import PropTypes from 'prop-types'; 4 - import { withRouteData } from 'react-static'; 5 3 6 - import Article from './article'; 4 + import Article, { ArticleStyling } from './article'; 7 5 import Header from './header'; 8 - import Sidebar from '../../components/sidebar'; 6 + import Sidebar, { SidebarStyling } from '../../components/sidebar'; 9 7 10 8 import burger from '../../assets/burger.svg'; 11 9 import closeButton from '../../assets/close.svg'; 12 10 13 - export const Container = styled.div` 11 + const Container = styled.div` 12 + position: relative; 14 13 display: flex; 15 14 flex-direction: row; 16 15 ··· 36 35 } 37 36 `; 38 37 39 - const Docs = props => { 38 + const Docs = ({ isLoading, children }) => { 40 39 const [sidebarOpen, setSidebarOpen] = useState(false); 41 40 42 41 return ( ··· 47 46 sidebarOpen={sidebarOpen} 48 47 onClick={() => setSidebarOpen(prev => !prev)} 49 48 /> 50 - <Sidebar sidebarOpen={sidebarOpen} /> 51 - <Article>{props.children}</Article> 49 + {/* load just the styles if Suspense fallback in use */} 50 + {isLoading ? ( 51 + <> 52 + <SidebarStyling sidebarOpen={sidebarOpen} /> 53 + <ArticleStyling>{children}</ArticleStyling> 54 + </> 55 + ) : ( 56 + <> 57 + <Sidebar sidebarOpen={sidebarOpen} /> 58 + <Article>{children}</Article> 59 + </> 60 + )} 52 61 </Container> 53 62 </> 54 63 ); 55 64 }; 56 65 57 - Docs.propTypes = { 58 - location: PropTypes.object, 59 - params: PropTypes.object, 60 - sidebarHeaders: PropTypes.array, 61 - slug: PropTypes.string, 62 - toc: PropTypes.object, 63 - }; 64 - 65 - Docs.defaultProps = { 66 - params: null, 67 - }; 68 - 69 - export default withRouteData(Docs); 66 + export default Docs;
+19 -16
packages/site/src/screens/home/index.js
··· 1 1 import React from 'react'; 2 2 import styled from 'styled-components'; 3 + import { usePrefetch } from 'react-static'; 4 + import { useMarkdownTree } from 'react-static-plugin-md-pages'; 3 5 4 6 import Features from './features'; 5 7 import GetStarted from './get-started'; ··· 12 14 width: 100%; 13 15 `; 14 16 15 - class Home extends React.Component { 16 - render() { 17 - return ( 18 - <Container> 19 - <Header /> 20 - <Features 21 - featureArray={content.features} 22 - components={content.components} 23 - /> 24 - <GetStarted getStartedObj={content.getStarted} /> 25 - <MoreOSS ossArray={content.oss} /> 26 - <Footer /> 27 - </Container> 28 - ); 29 - } 30 - } 17 + const Home = () => { 18 + const ref = usePrefetch('docs'); 19 + useMarkdownTree(); 20 + 21 + return ( 22 + <Container ref={ref}> 23 + <Header /> 24 + <Features 25 + featureArray={content.features} 26 + components={content.components} 27 + /> 28 + <GetStarted getStartedObj={content.getStarted} /> 29 + <MoreOSS ossArray={content.oss} /> 30 + <Footer /> 31 + </Container> 32 + ); 33 + }; 31 34 32 35 export default Home;
-12
packages/site/src/scroll-to-top.js
··· 1 - import { useEffect } from 'react'; 2 - import { useLocation } from 'react-router'; 3 - 4 - export const ScrollToTop = () => { 5 - const { pathname } = useLocation(); 6 - 7 - useEffect(() => { 8 - window.scrollTo(0, 0); 9 - }, [pathname]); 10 - 11 - return null; 12 - };
+5 -1
packages/site/src/styles/global.js
··· 31 31 background: ${p => p.theme.colors.passiveBg}; 32 32 color: ${p => p.theme.colors.text}; 33 33 font-family: ${p => p.theme.fonts.body}; 34 - font-size: ${p => p.theme.fontSizes.body}; 35 34 line-height: ${p => p.theme.lineHeights.body}; 36 35 font-weight: ${p => p.theme.fontWeights.body}; 37 36 text-rendering: optimizeLegibility; 38 37 margin: 0; 39 38 padding: 0; 39 + 40 + font-size: ${p => p.theme.fontSizes.bodySmall}; 41 + @media ${p => p.theme.media.lg} { 42 + font-size: ${p => p.theme.fontSizes.body}; 43 + } 40 44 } 41 45 42 46 a {
+5 -4
packages/site/src/styles/theme.js
··· 20 20 border: '#ececec', 21 21 activeBorder: '#a2b1ff', 22 22 text: '#000000', 23 - heading: '#050617', 23 + heading: '#444444', 24 24 accent: '#566ac8', 25 25 code: '#403f53', 26 - passive: '#9999a6', 26 + passive: '#444444', 27 27 }; 28 28 29 29 export const layout = { 30 30 page: '144rem', 31 31 header: '4.8rem', 32 - stripes: '1rem', 33 - sidebar: '28rem', 32 + stripes: '0.7rem', 33 + sidebar: '26rem', 34 34 legend: '22rem', 35 35 logo: '12rem', 36 36 }; ··· 44 44 export const fontSizes = { 45 45 small: '0.9em', 46 46 body: '1.8rem', 47 + bodySmall: '1.5rem', 47 48 code: '0.8em', 48 49 h1: '3.45em', 49 50 h2: '2.11em',
+4
packages/site/static.config.js
··· 49 49 path: '/', 50 50 template: require.resolve('./src/screens/home'), 51 51 }, 52 + { 53 + path: '404', 54 + template: require.resolve('./src/screens/404'), 55 + }, 52 56 ], 53 57 };
+5 -9
yarn.lock
··· 10021 10021 source-map "^0.6.1" 10022 10022 supports-color "^6.1.0" 10023 10023 10024 - preact@^10.3.1: 10025 - version "10.3.1" 10026 - resolved "https://registry.yarnpkg.com/preact/-/preact-10.3.1.tgz#70a2cc5484ca727c992216dfc528907d240e0a05" 10027 - 10028 - preact@^10.3.3: 10024 + preact@^10.3.1, preact@^10.3.3: 10029 10025 version "10.3.3" 10030 10026 resolved "https://registry.yarnpkg.com/preact/-/preact-10.3.3.tgz#31a949cdc89dd1cf72bc2b94f80ad55d1ac8c7e6" 10031 10027 integrity sha512-8EWUuHuLhX48uK0acnnXwBL/ZyrgeadnyhxG6hFI85BhwmquyGwWzfj2SylCNdEyltkdgbY3FZzQOM2mG1leAg== ··· 10472 10468 dependencies: 10473 10469 object-is "^1.0.2" 10474 10470 10475 - react-static-plugin-md-pages@^0.1.3: 10476 - version "0.1.3" 10477 - resolved "https://registry.yarnpkg.com/react-static-plugin-md-pages/-/react-static-plugin-md-pages-0.1.3.tgz#2c019e9e5e407b5d7701669b9b4581d506662ab5" 10478 - integrity sha512-aONsWlmeZECJgAz5Er7Jw83RlGLXgf08OFMmn2e3+BADhbheKp7ZWvC50l3AP8jwRr6wslxCO/2kwx99GC0u6A== 10471 + react-static-plugin-md-pages@^0.1.7: 10472 + version "0.1.7" 10473 + resolved "https://registry.yarnpkg.com/react-static-plugin-md-pages/-/react-static-plugin-md-pages-0.1.7.tgz#13f3daf1ce32fef9a77d037600572aeb752340c8" 10474 + integrity sha512-Y17VFyrOBMi2FqfumB5a50RHu2TbckC9LL2GMotJjL0PhbdpJBhgL6vbjEdJXoJxjk2JR93/dyZZcJmXhSL5MA== 10479 10475 dependencies: 10480 10476 "@mdx-js/mdx" "^1.5.5" 10481 10477 "@mdx-js/react" "^1.5.5"