fix: finish converting all primer/react to sx
Luke Karrys committed
Oct 15, 2023 at 22:50 UTC
8582aa9343a7cd6b0da5d1592982237ee92d456e
25 files changed
+396
-418
.eslintrc.js
+1
@@ -14,6 +14,7 @@ module.exports = {
14
],
15
rules: {
16
'react/prop-types': 'off',
17
+ 'primer-react/no-system-props': ['error', {includeUtilityComponents: true}],
18
},
19
overrides: [
20
{
src/components/clipboard-copy.js
+1
-1
@@ -33,7 +33,7 @@ function ClipboardCopy({value}) {
33
announce(`Copied to clipboard`)
34
}}
35
>
36
- {copied ? <Octicon icon={CheckIcon} color="green.5" /> : <Octicon icon={CopyIcon} color="gray.7" />}
36
+ <Octicon icon={copied ? CheckIcon : CopyIcon} sx={{color: copied ? 'green.5' : 'gray.7'}} />
37
</CopyToClipboard>
38
)
39
}
src/components/container.js
+1
-7
@@ -1,12 +1,6 @@
1
import {Box} from '@primer/react'
2
import React from 'react'
3
4
-function Container({children}) {
5
- return (
6
- <Box width="100%" maxWidth={960} p={5} mx="auto">
7
- {children}
8
- </Box>
9
- )
10
-}
4
+const Container = ({children}) => <Box sx={{width: '100%', maxWidth: 960, p: 5, mx: 'auto'}}>{children}</Box>
5
6
export default Container
src/components/contributors.js
+3
-3
@@ -23,8 +23,8 @@ const pluralize = (word, count) => `${word}${count === 1 ? '' : 's'}`
23
function Contributors({logins, latestCommit}) {
24
return (
25
<div>
26
- <Box display="flex" alignItems="center">
27
- <Text mr={2}>
26
+ <Box sx={{display: 'flex', alignItems: 'center'}}>
27
+ <Text sx={{mr: 2}}>
28
{logins.length} {pluralize('contributor', logins.length)}
29
</Text>
30
{logins.map(login => (
@@ -37,7 +37,7 @@ function Contributors({logins, latestCommit}) {
37
))}
38
</Box>
39
{latestCommit ? (
40
- <Text fontSize={1} color="gray.7" mt={1}>
40
+ <Text sx={{fontSize: 1, color: 'gray.7', mt: 1}}>
41
Last edited by <Link href={`https://github.com/${latestCommit.login}`}>{latestCommit.login}</Link> on{' '}
42
<Link href={latestCommit.url}>{format(new Date(latestCommit.date))}</Link>
43
</Text>
src/components/dark-button.js
deleted
-26
@@ -1,26 +0,0 @@
1
-import React from 'react'
2
-import {Button, themeGet} from '@primer/react'
3
-import styled from 'styled-components'
4
-
5
-const ButtonOutline = props => <Button variant="outline" {...props} />
6
-
7
-const DarkButton = styled(ButtonOutline)`
8
- color: ${themeGet('colors.gray.2')};
9
- background-color: transparent;
10
- border: 1px solid ${themeGet('colors.gray.7')};
11
- box-shadow: none;
12
-
13
- &:hover {
14
- background-color: #cb0000;
15
- }
16
-
17
- &:focus {
18
- box-shadow: 0 0 0 3px rgba(214, 102, 102, 0.3);
19
- }
20
-
21
- &:active {
22
- background-color: #ba0000;
23
- }
24
-`
25
-
26
-export default DarkButton
src/components/drawer.js
+19
-15
@@ -17,36 +17,40 @@ const Drawer = ({isOpen, onDismiss, children}) => (
17
role="button"
18
tabIndex="0"
19
>
20
- <FocusOn returnFocus={true} onEscapeKey={() => onDismiss()}>
20
+ <FocusOn returnFocus={true} onEscapeKey={onDismiss}>
21
<Box
22
- position="fixed"
22
+ sx={{
23
+ position: 'fixed',
24
+ top: 0,
25
+ right: 0,
26
+ bottom: 0,
27
+ left: 0,
28
+ bg: 'rgba(0, 0, 0, 0.5)',
29
+ }}
30
key="overlay"
31
as={motion.div}
32
initial={{opacity: 0}}
33
animate={{opacity: 1}}
34
exit={{opacity: 0}}
35
transition={{type: 'tween'}}
29
- top={0}
30
- right={0}
31
- bottom={0}
32
- left={0}
33
- bg="rgba(0, 0, 0, 0.5)"
34
- onClick={() => onDismiss()}
36
+ onClick={onDismiss}
37
/>
38
<Box
37
- position="fixed"
39
+ sx={{
40
+ position: 'fixed',
41
+ top: 0,
42
+ right: 0,
43
+ bottom: 0,
44
+ bg: 'gray.0',
45
+ width: 300,
46
+ zIndex: 1,
47
+ }}
48
key="drawer"
49
as={motion.div}
50
initial={{x: '100%'}}
51
animate={{x: 0}}
52
exit={{x: '100%'}}
53
transition={{type: 'tween', duration: 0.2}}
44
- width={300}
45
- top={0}
46
- right={0}
47
- bottom={0}
48
- bg="gray.0"
49
- style={{zIndex: 1}}
54
>
55
{children}
56
</Box>
src/components/head.js
deleted
-27
@@ -1,27 +0,0 @@
1
-import React from 'react'
2
-import {Helmet} from 'react-helmet'
3
-import useSiteMetdata from '../hooks/use-site-metadata'
4
-import {useFrontmatter} from '../layout'
5
-
6
-function Head() {
7
- const fm = useFrontmatter()
8
- const siteMetadata = useSiteMetdata()
9
-
10
- const title = [fm.title, siteMetadata.title].filter(Boolean).join(' | ')
11
- const description = fm.description || siteMetadata.description
12
- const lang = fm.lang || siteMetadata.lang
13
-
14
- return (
15
- <Helmet>
16
- <title>{title}</title>
17
- <meta name="description" content={description} />
18
- <meta property="og:title" content={title} />
19
- <meta property="og:description" content={description} />
20
- <meta property="og:image" content={siteMetadata.imageUrl} />
21
- <meta property="twitter:card" content="summary_large_image" />
22
- <html lang={lang} />
23
- </Helmet>
24
- )
25
-}
26
-
27
-export default Head
src/components/header.js
+33
-18
@@ -5,54 +5,69 @@ import styled from 'styled-components'
5
import MobileSearch from './mobile-search'
6
import NavDrawer from './nav-drawer'
7
import Search from './search'
8
-import NpmLogo from './npm-logo'
8
import useSearch from '../hooks/use-search'
9
import useSiteMetadata from '../hooks/use-site-metadata'
10
import headerNavItems from '../header-nav.yml'
12
-import {HEADER_HEIGHT} from '../constants'
11
+import {HEADER_HEIGHT, NPM_RED} from '../constants'
12
13
const NpmHeaderBar = styled(Box)`
14
height: 10px;
15
background-image: linear-gradient(139deg, #fb8817, #ff4b01, #c12127, #e02aff);
16
`
17
18
+const NpmLogo = ({size, style}) => (
19
+ <svg
20
+ height={size}
21
+ width={size}
22
+ viewBox="0 0 700 700"
23
+ fill="currentColor"
24
+ style={{color: NPM_RED, ...style}}
25
+ aria-hidden="true"
26
+ >
27
+ <polygon fill={NPM_RED} points="0,700 700,700 700,0 0,0" />
28
+ <polygon fill="#ffffff" points="150,550 350,550 350,250 450,250 450,550 550,550 550,150 150,150 " />
29
+ </svg>
30
+)
31
+
32
function Header() {
33
const siteMetadata = useSiteMetadata()
34
const search = useSearch()
35
36
return (
24
- <Box position="sticky" top={0} sx={{zIndex: 1}} role="banner">
37
+ <Box sx={{top: 0, position: 'sticky', zIndex: 1}} role="banner">
38
<NpmHeaderBar />
39
<Box
27
- display="flex"
28
- height={HEADER_HEIGHT}
29
- px={[3, null, null, 4]}
30
- alignItems="center"
31
- justifyContent="space-between"
32
- bg="#333333"
40
+ sx={{
41
+ display: 'flex',
42
+ height: HEADER_HEIGHT,
43
+ px: [3, null, null, 4],
44
+ alignItems: 'center',
45
+ justifyContent: 'space-between',
46
+ bg: '#333333',
47
+ }}
48
>
34
- <Box display="flex" alignItems="center">
49
+ <Box sx={{display: 'flex', alignItems: 'center'}}>
50
<Link
51
as={GatsbyLink}
52
to="/"
38
- style={{
53
+ sx={{
54
+ mr: 4,
55
color: '#dddddd',
56
fontWeight: '600',
57
display: 'flex',
58
alignItems: 'center',
59
}}
44
- sx={{mr: 4}}
60
>
46
- <NpmLogo size="32" style={{color: '#cb0000', marginRight: '16px'}} />
61
+ <NpmLogo size="32" sx={{mr: '16px'}} />
62
{siteMetadata.title}
63
</Link>
49
- <Box display={['none', null, null, 'block']} ml={4}>
64
+ <Box sx={{display: ['none', null, null, 'block'], ml: 4}}>
65
<Search {...search} />
66
</Box>
67
</Box>
53
- <Box display="flex">
54
- <Box display={['none', null, null, 'block']}>
55
- <Box display="flex" alignItems="center" color="gray.2">
68
+ <Box sx={{display: 'flex'}}>
69
+ <Box sx={{display: ['none', null, null, 'block']}}>
70
+ <Box sx={{display: 'flex', alignItems: 'center', color: 'gray.2'}}>
71
{headerNavItems.map((item, index) => (
72
<Link key={index} href={item.url} sx={{display: 'block', color: 'inherit', ml: 4}}>
73
{item.title}
@@ -60,7 +75,7 @@ function Header() {
75
))}
76
</Box>
77
</Box>
63
- <Box display={['flex', null, null, 'none']}>
78
+ <Box sx={{display: ['flex', null, null, 'none']}}>
79
<MobileSearch {...search} />
80
<NavDrawer />
81
</Box>
src/components/mobile-search.js
+33
-24
@@ -1,9 +1,8 @@
1
import React from 'react'
2
-import {Box} from '@primer/react'
2
+import {Button, Box} from '@primer/react'
3
import {XIcon, SearchIcon} from '@primer/octicons-react'
4
import {AnimatePresence, motion} from 'framer-motion'
5
import {FocusOn} from 'react-focus-on'
6
-import DarkButton from './dark-button'
6
import DarkTextInput from './dark-text-input'
7
import SearchResults from './search-results'
8
import useSiteMetadata from '../hooks/use-site-metadata'
@@ -19,23 +18,34 @@ function MobileSearch({onDismiss, ...props}) {
18
19
return (
20
<FocusOn returnFocus={true} onEscapeKey={handleDismiss}>
22
- <Box position="fixed" top="10px" left={0} right={0} bottom={0} zIndex={1}>
21
+ <Box
22
+ sx={{
23
+ position: 'fixed',
24
+ top: '10px',
25
+ left: 0,
26
+ right: 0,
27
+ bottom: 0,
28
+ zIndex: 1,
29
+ }}
30
+ >
31
<Box
24
- position="absolute"
32
+ sx={{
33
+ position: 'absolute',
34
+ top: 0,
35
+ left: 0,
36
+ right: 0,
37
+ bottom: 0,
38
+ bg: 'rgba(0,0,0,0.5)',
39
+ zIndex: -1,
40
+ }}
41
as={motion.div}
42
initial={{opacity: 0}}
43
animate={{opacity: 1}}
44
exit={{opacity: 0}}
29
- top={0}
30
- left={0}
31
- right={0}
32
- bottom={0}
33
- bg="rgba(0,0,0,0.5)"
34
- zIndex={-1}
45
onClick={handleDismiss}
46
/>
37
- <Box display="flex" flexDirection="column" height={isOpen ? '100%' : 'auto'}>
38
- <Box display="flex" bg="gray.9" color="white" p={3} flex="0 0 auto">
47
+ <Box sx={{display: 'flex', flexDirection: 'column', height: isOpen ? '100%' : 'auto'}}>
48
+ <Box sx={{display: 'flex', bg: 'gray.9', color: 'white', p: 3, flex: '0 0 auto'}}>
49
<motion.div
50
initial={{scaleX: 0.1}}
51
animate={{scaleX: 1}}
@@ -46,27 +56,26 @@ function MobileSearch({onDismiss, ...props}) {
56
<DarkTextInput
57
{...getInputProps({
58
placeholder: `Search ${siteMetadata.title}`,
49
- width: '100%',
59
'aria-label': `Search ${siteMetadata.title}`,
60
+ width: '100%',
61
})}
62
/>
63
</motion.div>
54
- <DarkButton ml={3} aria-label="Cancel" onClick={handleDismiss}>
64
+ <Button sx={{ml: 3}} aria-label="Cancel" onClick={handleDismiss}>
65
<XIcon />
56
- </DarkButton>
66
+ </Button>
67
</Box>
68
<Box
59
- display="flex"
60
- {...getMenuProps({
69
+ {...getMenuProps()}
70
+ sx={{
71
+ display: 'flex',
72
bg: 'white',
73
py: isOpen ? 1 : 0,
74
flexDirection: 'column',
75
flex: '1 1 auto',
65
- style: {
66
- overflow: 'auto',
67
- WebkitOverflowScrolling: 'touch',
68
- },
69
- })}
76
+ overflow: 'auto',
77
+ WebkitOverflowScrolling: 'touch',
78
+ }}
79
>
80
{isOpen ? <SearchResults {...{results, getItemProps, highlightedIndex}} /> : null}
81
</Box>
@@ -81,9 +90,9 @@ function MobileSearchWrapper(props) {
90
91
return (
92
<>
84
- <DarkButton aria-label="Search" aria-expanded={isOpen} onClick={() => setIsOpen(true)}>
93
+ <Button aria-label="Search" aria-expanded={isOpen} onClick={() => setIsOpen(true)}>
94
<SearchIcon />
86
- </DarkButton>
95
+ </Button>
96
<AnimatePresence>
97
{isOpen ? <MobileSearch onDismiss={() => setIsOpen(false)} {...props} /> : null}
98
</AnimatePresence>
src/components/nav-drawer.js
+38
-31
@@ -1,11 +1,9 @@
1
import React from 'react'
2
-import {Box, Link} from '@primer/react'
2
+import {Button, Box, Link} from '@primer/react'
3
import {XIcon, ThreeBarsIcon} from '@primer/octicons-react'
4
import {Link as GatsbyLink} from 'gatsby'
5
-import DarkButton from './dark-button'
5
import Drawer from './drawer'
6
import NavItems from './nav-items'
8
-import navItems from '../nav.yml'
7
import headerNavItems from '../header-nav.yml'
8
import useSiteMetadata from '../hooks/use-site-metadata'
9
import {useIsMobile} from '../hooks/use-breakpoint'
@@ -31,51 +29,60 @@ function NavDrawer() {
29
30
return (
31
<>
34
- <DarkButton aria-label="Menu" aria-expanded={isOpen} onClick={setOpen} ml={3}>
32
+ <Button aria-label="Menu" aria-expanded={isOpen} onClick={setOpen} sx={{ml: 3}}>
33
<ThreeBarsIcon />
36
- </DarkButton>
34
+ </Button>
35
<Drawer isOpen={isOpen} onDismiss={setClose}>
36
<Box
39
- display="flex"
40
- flexDirection="column"
41
- height="100%"
42
- bg="gray.0"
43
- style={{overflow: 'auto', WebkitOverflowScrolling: 'touch'}}
37
+ sx={{
38
+ display: 'flex',
39
+ flexDirection: 'column',
40
+ height: '100%',
41
+ bg: 'gray.0',
42
+ overflow: 'auto',
43
+ WebkitOverflowScrolling: 'touch',
44
+ }}
45
>
45
- <Box display="flex" flexDirection="column" flex="1 0 auto" color="gray.7" bg="gray.0">
46
- <Box borderStyle="solid" borderWidth={0} borderRadius={0} borderBottomWidth={1} borderColor="gray.7">
46
+ <Box sx={{display: 'flex', flexDirection: 'column', flex: '1 0 auto', color: 'gray.7', bg: 'gray.0'}}>
47
+ <Box
48
+ sx={{borderStyle: 'solid', borderWidth: 0, borderRadius: 0, borderBottomWidth: 1, borderColor: 'gray.7'}}
49
+ >
50
<Box
48
- display="flex"
49
- py={3}
50
- pl={4}
51
- pr={3}
52
- alignItems="center"
53
- justifyContent="space-between"
54
- color="gray.1"
55
- bg="gray.9"
51
+ sx={{
52
+ display: 'flex',
53
+ py: 3,
54
+ pl: 4,
55
+ pr: 3,
56
+ alignItems: 'center',
57
+ justifyContent: 'space-between',
58
+ color: 'gray.1',
59
+ bg: 'gray.9',
60
+ }}
61
>
62
<Link as={GatsbyLink} to="/" sx={{display: 'inline-block', color: 'inherit'}}>
63
{siteMetadata.title}
64
</Link>
60
- <DarkButton aria-label="Close" onClick={setClose}>
65
+ <Button aria-label="Close" onClick={setClose}>
66
<XIcon />
62
- </DarkButton>
67
+ </Button>
68
</Box>
69
</Box>
65
- <Box display="flex" flexDirection="column">
66
- <NavItems items={navItems} />
70
+ <Box sx={{display: 'flex', flexDirection: 'column'}}>
71
+ <NavItems />
72
</Box>
73
</Box>
69
- <Box display="flex" flexDirection="column" flex="1 0 auto" color="gray.1" bg="gray.9">
74
+ <Box sx={{display: 'flex', flexDirection: 'column', flex: '1 0 auto', color: 'gray.1', bg: 'gray.9'}}>
75
{headerNavItems.map((item, index) => (
76
<Box
72
- borderStyle="solid"
77
key={item.title}
74
- borderWidth={0}
75
- borderRadius={0}
76
- borderTopWidth={index !== 0 ? 1 : 0}
77
- borderColor="gray.7"
78
- p={4}
78
+ sx={{
79
+ borderStyle: 'solid',
80
+ borderWidth: 0,
81
+ borderRadius: 0,
82
+ borderTopWidth: index !== 0 ? 1 : 0,
83
+ borderColor: 'gray.7',
84
+ p: 4,
85
+ }}
86
>
87
<Link key={index} href={item.url} sx={{color: 'inherit', display: 'block'}}>
88
{item.title}
src/components/nav-items.js
+80
-95
@@ -1,6 +1,6 @@
1
import React from 'react'
2
import {Link as GatsbyLink} from 'gatsby'
3
-import {Box, StyledOcticon, Link, themeGet} from '@primer/react'
3
+import {Box, Octicon, Link, themeGet} from '@primer/react'
4
import {LinkExternalIcon} from '@primer/octicons-react'
5
import styled from 'styled-components'
6
import getNav from '../util/get-nav'
@@ -18,6 +18,19 @@ const ActiveLink = ({className, children, ...props}) => (
18
</Link>
19
)
20
21
+const withItems = Component => {
22
+ const WithItems = ({parent, path}) => {
23
+ if (!parent || getNav.isActiveUrl(path, parent.url)) {
24
+ const items = getNav.getHierarchy(parent, {path, hideVariants: true})
25
+ if (items) {
26
+ return <Component items={items} path={path} />
27
+ }
28
+ }
29
+ return null
30
+ }
31
+ return WithItems
32
+}
33
+
34
const NavLink = styled(ActiveLink)`
35
color: inherit;
36
text-decoration: none;
@@ -35,6 +48,34 @@ const TopLevelLink = styled(NavLink)`
48
color: ${themeGet('colors.gray.8')};
49
}
50
`
51
+
52
+const TopLevelItems = withItems(({items, path}) => (
53
+ <>
54
+ {items.map(item => (
55
+ <Box
56
+ key={item.title}
57
+ role="listitem"
58
+ sx={{
59
+ borderStyle: 'solid',
60
+ borderColor: 'border.default',
61
+ borderWidth: 0,
62
+ borderRadius: 0,
63
+ borderTopWidth: 1,
64
+ py: 3,
65
+ px: 4,
66
+ }}
67
+ >
68
+ <Box sx={{display: 'flex', flexDirection: 'column'}}>
69
+ <TopLevelLink to={item.url} key={item.title}>
70
+ {item.title}
71
+ </TopLevelLink>
72
+ <SecondLevelItems parent={item} path={path} />
73
+ </Box>
74
+ </Box>
75
+ ))}
76
+ </>
77
+))
78
+
79
const SecondLevelLink = styled(NavLink)`
80
display: block;
81
font-size: ${themeGet('fontSizes.1')};
@@ -47,6 +88,28 @@ const SecondLevelLink = styled(NavLink)`
88
}
89
`
90
91
+const Description = styled(Box)`
92
+ & {
93
+ color: ${themeGet('colors.gray.6')};
94
+ font-size: 0.8em;
95
+ font-weight: normal;
96
+ }
97
+`
98
+
99
+const SecondLevelItems = withItems(({items, path}) => (
100
+ <Box sx={{display: 'flex', flexDirection: 'column', mt: 2}} role="list">
101
+ {items.map(item => (
102
+ <Box key={item.title} role="listitem">
103
+ <SecondLevelLink key={item.url} to={item.url}>
104
+ {item.title}
105
+ {item.description ? <Description>{item.description}</Description> : null}
106
+ </SecondLevelLink>
107
+ <ThirdLevelItems parent={item} path={path} />
108
+ </Box>
109
+ ))}
110
+ </Box>
111
+))
112
+
113
const ThirdLevelLink = styled(NavLink)`
114
display: block;
115
font-size: ${themeGet('fontSizes.1')};
@@ -62,108 +125,30 @@ const ThirdLevelLink = styled(NavLink)`
125
}
126
`
127
65
-const Description = styled(Box)`
66
- & {
67
- color: ${themeGet('colors.gray.6')};
68
- font-size: 0.8em;
69
- font-weight: normal;
70
- }
71
-`
72
-
73
-function topLevelItems(items, path) {
74
- if (items == null) {
75
- return null
76
- }
77
-
78
- return (
79
- <>
80
- {items.map(item => {
81
- const children = getNav.isActiveUrl(path, item.url)
82
- ? getNav.getHierarchy(item, {path, hideVariants: true})
83
- : null
84
-
85
- return (
86
- <Box
87
- borderStyle="solid"
88
- borderColor="border.default"
89
- key={item.title}
90
- borderWidth={0}
91
- borderRadius={0}
92
- borderTopWidth={1}
93
- py={3}
94
- px={4}
95
- role="listitem"
96
- >
97
- <Box display="flex" flexDirection="column">
98
- <TopLevelLink to={item.url} key={item.title}>
99
- {item.title}
100
- </TopLevelLink>
101
- {secondLevelItems(children, path)}
102
- </Box>
103
- </Box>
104
- )
105
- })}
106
- </>
107
- )
108
-}
109
-
110
-function secondLevelItems(items, path) {
111
- if (items == null) {
112
- return null
113
- }
114
-
115
- return (
116
- <Box display="flex" flexDirection="column" mt={2} role="list">
117
- {items.map(item => {
118
- const children = getNav.isActiveUrl(path, item.url)
119
- ? getNav.getHierarchy(item, {path, hideVariants: true})
120
- : null
121
- return (
122
- <Box key={item.title} role="listitem">
123
- <SecondLevelLink key={item.url} to={item.url}>
124
- {item.title}
125
- {item.description != null ? <Description>{item.description}</Description> : null}
126
- </SecondLevelLink>
127
- {thirdLevelItems(children, path)}
128
- </Box>
129
- )
130
- })}
131
- </Box>
132
- )
133
-}
134
-
135
-function thirdLevelItems(items) {
136
- if (items == null) {
137
- return null
138
- }
139
-
140
- return (
141
- <Box display="flex" flexDirection="column" mt={2} role="list">
142
- {items.map(item => (
143
- <Box key={item.title} role="listitem">
144
- <ThirdLevelLink key={item.url} to={item.url}>
145
- {item.title}
146
- </ThirdLevelLink>
147
- </Box>
148
- ))}
149
- </Box>
150
- )
151
-}
128
+const ThirdLevelItems = withItems(({items}) => (
129
+ <Box sx={{display: 'flex', flexDirection: 'column', mt: 2}} role="list">
130
+ {items.map(item => (
131
+ <Box key={item.title} role="listitem">
132
+ <ThirdLevelLink key={item.url} to={item.url}>
133
+ {item.title}
134
+ </ThirdLevelLink>
135
+ </Box>
136
+ ))}
137
+ </Box>
138
+))
139
140
function NavItems() {
154
- const location = useLocation()
141
const {repositoryUrl} = usePageContext()
156
- const path = getNav.getLocation(location.pathname)
157
- const items = getNav.getHierarchy(null, {path, hideVariants: true})
142
+ const location = useLocation()
143
144
return (
145
<>
161
- {topLevelItems(items, path)}
162
- <Box borderStyle="solid" borderColor="border.default" borderWidth={0} borderTopWidth={1} py={3} px={4}>
146
+ <TopLevelItems path={getNav.getLocation(location.pathname)} />
147
+ <Box sx={{borderStyle: 'solid', borderColor: 'border.default', borderWidth: 0, borderTopWidth: 1, py: 3, px: 4}}>
148
<Link href={repositoryUrl} sx={{color: 'inherit'}}>
164
- <Box display="flex" justifyContent="space-between" alignItems="center" color="gray.5">
149
+ <Box sx={{display: 'flex', justifyContent: 'space-between', alignItems: 'center', color: 'gray.5'}}>
150
GitHub
166
- <StyledOcticon icon={LinkExternalIcon} color="gray.5" />
151
+ <Octicon icon={LinkExternalIcon} sx={{color: 'gray.5'}} />
152
</Box>
153
</Link>
154
</Box>
src/components/npm-logo.js
deleted
-12
@@ -1,12 +0,0 @@
1
-import React from 'react'
2
-
3
-const NpmLogo = ({size, style}) => {
4
- return (
5
- <svg height={size} width={size} viewBox="0 0 700 700" fill="currentColor" style={style} aria-hidden="true">
6
- <polygon fill="#cb0000" points="0,700 700,700 700,0 0,0" />
7
- <polygon fill="#ffffff" points="150,550 350,550 350,250 450,250 450,550 550,550 550,150 150,150 " />
8
- </svg>
9
- )
10
-}
11
-
12
-export default NpmLogo
src/components/page-footer.js
+12
-10
@@ -7,18 +7,20 @@ function PageFooter({editUrl, contributors = {}}) {
7
const {logins = [], latestCommit} = contributors
8
return editUrl || logins.length ? (
9
<Box
10
- borderStyle="solid"
11
- borderColor="border.default"
12
- borderRadius={2}
13
- borderWidth={0}
14
- borderTopWidth={1}
15
- mt={8}
16
- py={5}
10
+ sx={{
11
+ borderStyle: 'solid',
12
+ borderColor: 'border.default',
13
+ borderRadius: 2,
14
+ borderWidth: 0,
15
+ borderTopWidth: 1,
16
+ mt: 8,
17
+ py: 5,
18
+ }}
19
>
18
- <Box display="grid" gridGap={4}>
19
- {editUrl != null ? (
20
+ <Box sx={{display: 'grid', gap: 4}}>
21
+ {editUrl ? (
22
<Link href={editUrl}>
21
- <Octicon icon={PencilIcon} mr={2} />
23
+ <Octicon icon={PencilIcon} sx={{mr: 2}} />
24
Edit this page on GitHub
25
</Link>
26
) : null}
src/components/search-results.js
+20
-21
@@ -3,12 +3,24 @@ import {Box, Text} from '@primer/react'
3
import useSiteMetadata from '../hooks/use-site-metadata'
4
import getNav from '../util/get-nav'
5
6
-function SearchResults({results, getItemProps, highlightedIndex}) {
6
+const Breadcrumbs = ({item, highlighted}) => {
7
const siteMetadata = useSiteMetadata()
8
+ const hierarchy = getNav.getItemHierarchy(item.path)
9
+
10
+ const text = hierarchy
11
+ ? hierarchy
12
+ .slice(0, -1)
13
+ .map(item => item.shortName || item.title)
14
+ .join(' / ')
15
+ : siteMetadata.shortName
16
17
+ return <Text sx={{fontSize: 0, color: highlighted ? 'blue.2' : 'gray.7'}}>{text}</Text>
18
+}
19
+
20
+function SearchResults({results, getItemProps, highlightedIndex}) {
21
if (results.length === 0) {
22
return (
11
- <Text as="div" p={3} fontSize={1} color="gray.7" width="100%">
23
+ <Text as="div" sx={{p: 3, fontSize: 1, color: 'gray.7', width: '100%'}}>
24
No results
25
</Text>
26
)
@@ -16,36 +28,23 @@ function SearchResults({results, getItemProps, highlightedIndex}) {
28
29
return results.map((item, index) => (
30
<Box
19
- display="flex"
31
key={item.path}
21
- {...getItemProps({
22
- item,
32
+ sx={{
33
+ display: 'flex',
34
flexDirection: 'column',
35
flex: '0 0 auto',
36
px: 3,
37
py: 2,
38
color: highlightedIndex === index ? 'white' : 'gray.8',
39
bg: highlightedIndex === index ? 'blue.5' : 'transparent',
29
- style: {cursor: 'pointer'},
30
- })}
40
+ cursor: 'pointer',
41
+ }}
42
+ {...getItemProps({item})}
43
>
32
- <Text fontSize={0} color={highlightedIndex === index ? 'blue.2' : 'gray.7'}>
33
- {getBreadcrumbs(siteMetadata.shortName, item.path).join(' / ')}
34
- </Text>
44
+ <Breadcrumbs item={item} highlighted={highlightedIndex === index} />
45
{item.title}
46
</Box>
47
))
48
}
49
40
-function getBreadcrumbs(siteTitle, path) {
41
- const hierarchy = getNav.getItemHierarchy(path)
42
-
43
- if (hierarchy) {
44
- hierarchy.pop()
45
- return hierarchy.map(item => (item.shortName ? item.shortName : item.title))
46
- } else {
47
- return [siteTitle]
48
- }
49
-}
50
-
50
export default SearchResults
src/components/search.js
+14
-12
@@ -9,11 +9,11 @@ function Search(props) {
9
const {getInputProps, getMenuProps, isOpen, results, getItemProps, highlightedIndex} = props
10
11
return (
12
- <Box position="relative">
12
+ <Box sx={{position: 'relative'}}>
13
<DarkTextInput
14
+ sx={{width: '240px'}}
15
{...getInputProps({
16
placeholder: `Search ${siteMetadata.title}`,
16
- width: 240,
17
'aria-label': `Search ${siteMetadata.title}`,
18
})}
19
/>
@@ -27,16 +27,18 @@ function Search(props) {
27
>
28
{isOpen ? (
29
<Box
30
- borderWidth={1}
31
- borderStyle="solid"
32
- borderColor="border.default"
33
- borderRadius={2}
34
- minWidth={300}
35
- maxHeight="70vh"
36
- py={1}
37
- boxShadow="medium"
38
- bg="white"
39
- style={{overflow: 'auto'}}
30
+ sx={{
31
+ borderWidth: 1,
32
+ borderStyle: 'solid',
33
+ borderColor: 'border.default',
34
+ borderRadius: 2,
35
+ minWidth: '300px',
36
+ maxHeight: '70vh',
37
+ py: 1,
38
+ boxShadow: 'medium',
39
+ bg: 'white',
40
+ overflow: 'auto',
41
+ }}
42
>
43
<SearchResults {...{results, getItemProps, highlightedIndex}} />
44
</Box>
src/components/sidebar.js
+19
-16
@@ -1,30 +1,33 @@
1
import {Box} from '@primer/react'
2
import React from 'react'
3
import NavItems from './nav-items'
4
-import navItems from '../nav.yml'
4
import {HEADER_HEIGHT} from '../constants'
5
6
const Sidebar = () => (
7
<Box
9
- position="sticky"
10
- top={HEADER_HEIGHT}
11
- height={`calc(100vh - ${HEADER_HEIGHT}px)`}
12
- minWidth={260}
13
- color="gray.8"
14
- bg="gray.0"
8
role="navigation"
9
+ sx={{
10
+ position: 'sticky',
11
+ top: `${HEADER_HEIGHT}px`,
12
+ height: `calc(100vh - ${HEADER_HEIGHT}px)`,
13
+ minWidth: 260,
14
+ color: 'gray.8',
15
+ bg: 'gray.0',
16
+ }}
17
>
18
<Box
18
- borderStyle="solid"
19
- borderColor="border.default"
20
- borderWidth={0}
21
- borderRightWidth={1}
22
- borderRadius={0}
23
- height="100%"
24
- style={{overflow: 'auto'}}
19
+ sx={{
20
+ borderStyle: 'solid',
21
+ borderColor: 'border.default',
22
+ borderWidth: 0,
23
+ borderRightWidth: 1,
24
+ borderRadius: 0,
25
+ height: '100%',
26
+ overflow: 'auto',
27
+ }}
28
>
26
- <Box display="flex" flexDirection="column" role="list">
27
- <NavItems items={navItems} />
29
+ <Box sx={{display: 'flex', flexDirection: 'column'}} role="list">
30
+ <NavItems />
31
</Box>
32
</Box>
33
</Box>
src/components/table-of-contents.js
+37
-40
@@ -1,5 +1,5 @@
1
import React from 'react'
2
-import {Box, Link, Text, Octicon, Details} from '@primer/react'
2
+import {Box, Link, Text, Octicon, Details, useDetails} from '@primer/react'
3
import {ChevronDownIcon, ChevronRightIcon} from '@primer/octicons-react'
4
import {usePageContext} from '../layout'
5
import {HEADER_HEIGHT} from '../constants'
@@ -9,13 +9,11 @@ const TableOfContents = ({items, depth = 0, labelId}) => (
9
key={items}
10
as="ul"
11
role="list"
12
- m={0}
13
- p={0}
14
- css={{listStyle: 'none', lineHeight: '1.4em'}}
12
+ sx={{m: 0, p: 0, listStyle: 'none', lineHeight: '1.4em'}}
13
aria-labelledby={labelId}
14
>
15
{items.map(item => (
18
- <Box as="li" role="listitem" key={item.url} pl={depth > 0 ? 3 : 0}>
16
+ <Box as="li" role="listitem" key={item.url} sx={{pl: depth > 0 ? 3 : 0}}>
17
<Link key={item.title} href={item.url} sx={{display: 'inline-block', py: 1, color: 'gray.6'}}>
18
{item.title}
19
</Link>
@@ -25,48 +23,47 @@ const TableOfContents = ({items, depth = 0, labelId}) => (
23
</Box>
24
)
25
28
-const withTableOfContent = Component => {
29
- const TOC = props => {
26
+const withTableOfContents = Component => {
27
+ const WithTableOfContents = props => {
28
const {tableOfContents} = usePageContext()
31
- if (!tableOfContents) {
32
- return null
33
- }
34
- return <Component {...props} items={tableOfContents} />
29
+ return tableOfContents ? <Component {...props} items={tableOfContents} /> : null
30
}
36
- return TOC
31
+ return WithTableOfContents
32
}
33
39
-export const Mobile = withTableOfContent(({items}) => (
40
- <Box display={['block', null, 'none']} mb={3}>
41
- <Details>
42
- {({open}) => (
43
- <>
44
- <Text as="summary" fontWeight="bold">
45
- <Octicon icon={open ? ChevronDownIcon : ChevronRightIcon} mr={2} />
46
- Table of contents
47
- </Text>
48
- <Box pt={1}>
49
- <TableOfContents items={items} />
50
- </Box>
51
- </>
52
- )}
53
- </Details>
54
- </Box>
55
-))
34
+export const Mobile = withTableOfContents(({items}) => {
35
+ const {getDetailsProps, open} = useDetails({})
36
+ return (
37
+ <Box sx={{display: ['block', null, 'none'], mb: 3}}>
38
+ <Details {...getDetailsProps()}>
39
+ <Text as="summary" sx={{fontWeight: 'bold'}}>
40
+ <Octicon icon={open ? ChevronDownIcon : ChevronRightIcon} sx={{mr: 2}} />
41
+ Table of contents
42
+ </Text>
43
+ <Box sx={{pt: 1}}>
44
+ <TableOfContents items={items} />
45
+ </Box>
46
+ </Details>
47
+ </Box>
48
+ )
49
+})
50
57
-export const Desktop = withTableOfContent(({items}) => (
51
+export const Desktop = withTableOfContents(({items}) => (
52
<Box
59
- display={['none', null, 'block']}
60
- css={{gridArea: 'table-of-contents', overflow: 'auto'}}
61
- position="sticky"
62
- top={HEADER_HEIGHT + 24}
63
- mt="6px"
64
- maxHeight={`calc(100vh - ${HEADER_HEIGHT}px - 24px)`}
65
- pr={1}
66
- pl={1}
67
- pb={1}
53
+ sx={{
54
+ display: ['none', null, 'block'],
55
+ position: 'sticky',
56
+ top: `${HEADER_HEIGHT + 24}px`,
57
+ maxHeight: `calc(100vh - ${HEADER_HEIGHT}px - 24px)`,
58
+ mt: '6px',
59
+ pr: 1,
60
+ pl: 1,
61
+ pb: 1,
62
+ gridArea: 'table-of-contents',
63
+ overflow: 'auto',
64
+ }}
65
>
69
- <Text display="inline-block" fontWeight="bold" mb={1} id="table-of-content-label">
66
+ <Text id="table-of-content-label" sx={{display: 'inline-block', fontWeight: 'bold', mb: 1}}>
67
Table of contents
68
</Text>
69
<TableOfContents items={items} labelId="table-of-content-label" />
src/constants.js
+2
@@ -1,3 +1,5 @@
1
export const HEADER_HEIGHT = 66
2
3
export const SKIP_NAV = 'skip-nav'
4
+
5
+export const NPM_RED = '#cb0000'
src/layout.js
+27
-6
@@ -1,10 +1,11 @@
1
import React from 'react'
2
+import {Helmet} from 'react-helmet'
3
import {Box} from '@primer/react'
4
import Slugger from 'github-slugger'
4
-import Head from './components/head'
5
import Header from './components/header'
6
import Sidebar from './components/sidebar'
7
import {SKIP_NAV} from './constants'
8
+import useSiteMetdata from './hooks/use-site-metadata'
9
10
const SluggerContext = React.createContext(null)
11
const PageContext = React.createContext(null)
@@ -13,21 +14,41 @@ const LocationContext = React.createContext(null)
14
export const useSlugger = () => React.useContext(SluggerContext)
15
export const usePageContext = () => React.useContext(PageContext)
16
export const useLocation = () => React.useContext(LocationContext)
16
-export const useFrontmatter = () => usePageContext().frontmatter
17
+
18
+const Head = () => {
19
+ const {frontmatter} = usePageContext()
20
+ const siteMetadata = useSiteMetdata()
21
+
22
+ const title = [frontmatter.title, siteMetadata.title].filter(Boolean).join(' | ')
23
+ const description = frontmatter.description || siteMetadata.description
24
+ const lang = frontmatter.lang || siteMetadata.lang
25
+
26
+ return (
27
+ <Helmet>
28
+ <title>{title}</title>
29
+ <meta name="description" content={description} />
30
+ <meta property="og:title" content={title} />
31
+ <meta property="og:description" content={description} />
32
+ <meta property="og:image" content={siteMetadata.imageUrl} />
33
+ <meta property="twitter:card" content="summary_large_image" />
34
+ <html lang={lang} />
35
+ </Helmet>
36
+ )
37
+}
38
39
const withLayout = Component => {
40
const LayoutProvider = props => (
41
<SluggerContext.Provider value={new Slugger()}>
42
<PageContext.Provider value={props.pageContext}>
43
<LocationContext.Provider value={props.location}>
23
- <Box display="flex" flexDirection="column" minHeight="100vh">
44
+ <Box sx={{display: 'flex', flexDirection: 'column', minHeight: '100vh'}}>
45
<Head />
46
<Header />
26
- <Box display="flex" flex="1 1 auto" flexDirection="row" css={{zIndex: 0}} role="main">
27
- <Box display={['none', null, null, 'block']}>
47
+ <Box sx={{display: 'flex', flex: '1 1 auto', flexDirection: 'row', zIndex: 0}} role="main">
48
+ <Box sx={{display: ['none', null, null, 'block']}}>
49
<Sidebar />
50
</Box>
30
- <Box id={SKIP_NAV}>
51
+ <Box sx={{width: '100%'}} id={SKIP_NAV}>
52
<Component {...props} />
53
</Box>
54
</Box>
src/layout/default.js
+20
-15
@@ -10,25 +10,30 @@ const Layout = ({children, pageContext: {frontmatter}}) => {
10
11
return (
12
<Box
13
- display="grid"
14
- maxWidth="100%"
15
- gridTemplateColumns={['100%', null, 'minmax(0, 65ch) 220px']}
16
- gridTemplateAreas={['"heading" "content"', null, '"heading table-of-contents" "content table-of-contents"']}
17
- gridColumnGap={[null, null, 6, 7]}
18
- gridRowGap={3}
19
- mx="auto"
20
- p={[5, 6, null, 7]}
21
- css={{alignItems: 'start', alignSelf: 'start'}}
13
role="region"
14
+ sx={{
15
+ display: 'grid',
16
+ maxWidth: '100%',
17
+ gridTemplateColumns: ['100%', null, 'minmax(0, 65ch) 220px'],
18
+ gridTemplateAreas: ['"heading" "content"', null, '"heading table-of-contents" "content table-of-contents"'],
19
+ columnGap: [null, null, 6, 7],
20
+ rowGap: 3,
21
+ mx: 'auto',
22
+ p: [5, 6, null, 7],
23
+ alignItems: 'start',
24
+ alignSelf: 'start',
25
+ }}
26
>
27
<Box css={{gridArea: 'heading'}}>
28
<Box
26
- borderStyle="solid"
27
- borderColor="border.default"
28
- borderWidth={0}
29
- borderBottomWidth={1}
30
- borderRadius={0}
31
- pb={2}
29
+ sx={{
30
+ borderStyle: 'solid',
31
+ borderColor: 'border.default',
32
+ borderWidth: 0,
33
+ borderBottomWidth: 1,
34
+ borderRadius: 0,
35
+ pb: 2,
36
+ }}
37
>
38
<Heading as="h1">{title}</Heading>
39
{description}
src/layout/hero.js
+1
-1
@@ -5,7 +5,7 @@ import Hero from '../components/hero'
5
import withLayout from '../layout'
6
7
const HeroLayout = ({children}) => (
8
- <Box width="100%">
8
+ <Box sx={{width: '100%'}}>
9
<Hero />
10
<Container>{children}</Container>
11
</Box>
src/mdx/code.js
+13
-11
@@ -10,9 +10,9 @@ function Code({className: language = '', children}) {
10
const {scrollRef, paddingRef, size} = useScrollSize()
11
12
return (
13
- <Box position="relative">
13
+ <Box sx={{position: 'relative'}}>
14
<div ref={paddingRef}>
15
- <Box position="absolute" top={0} right={0} p={2} zIndex={1}>
15
+ <Box sx={{position: 'absolute', top: 0, right: 0, p: 2, zIndex: 1}}>
16
<ClipboardCopy value={code} />
17
</Box>
18
</div>
@@ -20,16 +20,18 @@ function Code({className: language = '', children}) {
20
{({className, style, tokens, getLineProps, getTokenProps}) => (
21
<Box
22
tabIndex={0}
23
- borderWidth={1}
24
- borderStyle="solid"
25
- borderColor="border.default"
26
- borderRadius={2}
23
as="pre"
24
className={className}
29
- mt={0}
30
- mb={3}
31
- p={3}
32
- border={0}
25
+ sx={{
26
+ borderWidth: 1,
27
+ borderStyle: 'solid',
28
+ borderColor: 'border.default',
29
+ borderRadius: 2,
30
+ mt: 0,
31
+ mb: 3,
32
+ p: 3,
33
+ border: 0,
34
+ }}
35
style={{...style, overflow: 'auto'}}
36
>
37
{/* This is the scroll handle, it is supposed to be focused with keyboard and scroll a wide codebox horizontally */}
@@ -37,7 +39,7 @@ function Code({className: language = '', children}) {
39
{tokens.map((line, i) => (
40
<div key={i} {...getLineProps({line, key: i})}>
41
{line.map((token, key) => (
40
- <Text key={key} fontFamily="mono" fontSize={1} {...getTokenProps({token, key})} />
42
+ <Text key={key} sx={{fontFamily: 'mono', fontSize: 1}} {...getTokenProps({token, key})} />
43
))}
44
</div>
45
))}
src/mdx/index.js
+16
-16
@@ -232,14 +232,16 @@ export const Table = styled.table`
232
233
export const Note = ({children}) => (
234
<Box
235
- borderWidth={1}
236
- borderStyle="solid"
237
- borderRadius={0}
238
- borderColor="blue.1"
239
- backgroundColor="blue.0"
240
- px={3}
241
- py={2}
242
- my={4}
235
+ sx={{
236
+ borderWidth: 1,
237
+ borderStyle: 'solid',
238
+ borderRadius: 0,
239
+ borderColor: 'blue.1',
240
+ backgroundColor: 'blue.0',
241
+ px: 3,
242
+ py: 2,
243
+ my: 4,
244
+ }}
245
>
246
{React.Children.toArray(children).map((child, index, list) =>
247
React.cloneElement(child, {
@@ -252,19 +254,17 @@ export const Note = ({children}) => (
254
export const Prompt = ({children}) => (
255
<Box
256
as="pre"
255
- mt={0}
256
- mb={3}
257
- p={3}
258
- border={0}
259
- style={{
257
+ sx={{
258
+ mt: 0,
259
+ mb: 3,
260
+ p: 3,
261
+ border: 0,
262
color: 'rgb(57, 58, 52)',
263
backgroundColor: 'rgb(246, 248, 250)',
264
overflow: 'auto',
265
}}
266
>
265
- <Text fontFamily="mono" fontSize={1}>
266
- {children}
267
- </Text>
267
+ <Text sx={{fontFamily: 'mono', fontSize: 1}}>{children}</Text>
268
</Box>
269
)
270
src/mdx/nav-hierarchy.js
+1
-3
@@ -12,9 +12,7 @@ const HierarchyItem = ({item, currentDepth, ...props}) => {
12
<Link as={GatsbyLink} key={item.title} to={item.url}>
13
{item.title}
14
</Link>
15
- {item.description != null ? (
16
- <Box style={{fontSize: '0.85em', marginBottom: '0.5em'}}>{item.description}</Box>
17
- ) : null}
15
+ {item.description ? <Box style={{fontSize: '0.85em', marginBottom: '0.5em'}}>{item.description}</Box> : null}
16
{hierarchy ? <Hierarchy items={hierarchy} currentDepth={currentDepth + 1} {...props} /> : null}
17
</Box>
18
)
src/util/get-nav.js
+5
-8
@@ -144,14 +144,11 @@ const NavHierarchy = {
144
145
for (const item of items) {
146
if (item.variants) {
147
- const cloned = {}
148
- Object.assign(cloned, item)
149
-
150
- const variant = this.getCurrentOrDefaultVariant(item, props.path)
151
-
152
- cloned.url = variant.url
153
-
154
- updated.push(cloned)
147
+ const {url} = this.getCurrentOrDefaultVariant(item, props.path)
148
+ updated.push({
149
+ ...item,
150
+ url,
151
+ })
152
} else {
153
updated.push(item)
154
}