chore: Convert sx(deprecated) to style
Michael Smith committed
Jan 8, 2026 at 13:30 UTC
a9fd12fa43c9d73e7202c07028e2d70c276fd7c5
32 files changed
+853
-390
src/components/breadcrumbs.js
+3
-1
@@ -4,6 +4,8 @@ import {Link as GatsbyLink} from 'gatsby'
4
import * as getNav from '../util/get-nav'
5
import usePage from '../hooks/use-page'
6
7
+import * as styles from './breadcrumbs.module.css'
8
+
9
const BreadcrumbItem = ({item, path}) => {
10
const selected = getNav.isPathForItem(path, getNav.getItem(item.url))
11
@@ -23,7 +25,7 @@ const Breadcrumbs = () => {
25
}
26
27
return (
26
- <PrimerBreadcrumbs sx={{mb: 4}}>
28
+ <PrimerBreadcrumbs className={styles.PrimerBreadcrumbs}>
29
{items.map(item => (
30
<BreadcrumbItem key={item.url} item={item} path={pathname} />
31
))}
src/components/breadcrumbs.module.css
new
+3
@@ -0,0 +1,3 @@
1
+.PrimerBreadcrumbs {
2
+ margin-bottom: 24px;
3
+}
src/components/header.js
+12
-24
@@ -5,11 +5,13 @@ import * as Search from './search'
5
import NavDrawer from './nav-drawer'
6
import Link from './link'
7
import useSearch from '../hooks/use-search'
8
-import {HEADER_HEIGHT, HEADER_BAR, Z_INDEX} from '../constants'
8
+import {HEADER_BAR, Z_INDEX} from '../constants'
9
import headerNavItems from '../../content/header-nav.yml'
10
import {DarkTheme} from '../theme'
11
import SiteTitle from './site-title'
12
13
+import * as styles from './header.module.css'
14
+
15
const NpmHeaderBar = styled(Box)`
16
height: ${HEADER_BAR}px;
17
background-image: linear-gradient(139deg, #fb8817, #ff4b01, #c12127, #e02aff);
@@ -19,38 +21,24 @@ function Header() {
21
const search = useSearch()
22
23
return (
22
- <DarkTheme sx={{top: 0, position: 'sticky', zIndex: Z_INDEX.HEADER}}>
24
+ <DarkTheme style={{zIndex: Z_INDEX.HEADER}} className={styles.DarkTheme}>
25
<NpmHeaderBar />
24
- <Box
25
- as="header"
26
- sx={{
27
- display: 'flex',
28
- height: `${HEADER_HEIGHT}px`,
29
- px: [3, null, null, 4],
30
- alignItems: 'center',
31
- justifyContent: 'space-between',
32
- bg: 'canvas.default',
33
- border: '1px solid',
34
- borderLeftWidth: 0,
35
- borderRightWidth: 0,
36
- borderColor: 'border.muted',
37
- }}
38
- >
39
- <Box sx={{display: 'flex', alignItems: 'center'}}>
40
- <SiteTitle logo={true} sx={{mr: 4}} />
41
- <Box sx={{display: ['none', null, null, 'block'], ml: 4}}>
26
+ <Box as="header" className={styles.headerBox}>
27
+ <Box className={styles.Box}>
28
+ <SiteTitle logo={true} className={styles.SiteTitle} />
29
+ <Box className={styles.searchDesktop}>
30
<Search.Desktop {...search} />
31
</Box>
32
</Box>
45
- <Box sx={{display: 'flex'}}>
46
- <Box sx={{display: ['none', null, null, 'flex'], alignItems: 'center'}}>
33
+ <Box className={styles.Box_1}>
34
+ <Box className={styles.navDesktop}>
35
{headerNavItems.map((item, index) => (
48
- <Link key={index} href={item.url} sx={{display: 'block', ml: 4, color: 'fg.default'}}>
36
+ <Link key={index} href={item.url} className={styles.Link}>
37
{item.title}
38
</Link>
39
))}
40
</Box>
53
- <Box sx={{display: ['flex', null, null, 'none']}}>
41
+ <Box className={styles.navMobile}>
42
<Search.Mobile {...search} />
43
<NavDrawer />
44
</Box>
src/components/header.module.css
new
+82
@@ -0,0 +1,82 @@
1
+.Box {
2
+ display: flex;
3
+ align-items: center;
4
+}
5
+
6
+.Box_1 {
7
+ display: flex;
8
+}
9
+
10
+.DarkTheme {
11
+ top: 0;
12
+ position: sticky;
13
+}
14
+
15
+/* mr: 4 = 24px */
16
+.SiteTitle {
17
+ margin-right: 24px;
18
+}
19
+
20
+/* ml: 4 = 24px */
21
+/* color: 'fg.default' in dark_dimmed = #E1E4E8 */
22
+.Link {
23
+ display: block;
24
+ margin-left: 24px;
25
+ color: #e1e4e8;
26
+}
27
+
28
+/* px: [3, null, null, 4] = 16px base, 24px at lg */
29
+/* bg: 'canvas.default' in dark_dimmed theme = #333333 */
30
+.headerBox {
31
+ display: flex;
32
+ height: 56px;
33
+ padding-left: 16px;
34
+ padding-right: 16px;
35
+ align-items: center;
36
+ justify-content: space-between;
37
+ background-color: #333333;
38
+ border: 1px solid;
39
+ border-left-width: 0;
40
+ border-right-width: 0;
41
+ border-color: #444d56;
42
+}
43
+
44
+@media (min-width: 1012px) {
45
+ .headerBox {
46
+ padding-left: 24px;
47
+ padding-right: 24px;
48
+ }
49
+}
50
+
51
+/* ml: 4 = 24px */
52
+.searchDesktop {
53
+ display: none;
54
+ margin-left: 24px;
55
+}
56
+
57
+@media (min-width: 1012px) {
58
+ .searchDesktop {
59
+ display: block;
60
+ }
61
+}
62
+
63
+.navDesktop {
64
+ display: none;
65
+ align-items: center;
66
+}
67
+
68
+@media (min-width: 1012px) {
69
+ .navDesktop {
70
+ display: flex;
71
+ }
72
+}
73
+
74
+.navMobile {
75
+ display: flex;
76
+}
77
+
78
+@media (min-width: 1012px) {
79
+ .navMobile {
80
+ display: none;
81
+ }
82
+}
src/components/link.js
+18
-21
@@ -3,6 +3,10 @@ import {Link as PrimerLink} from '@primer/react'
3
import {Link as GatsbyLink} from 'gatsby'
4
import omit from '../util/omit'
5
6
+import * as styles from './link.module.css'
7
+
8
+import {clsx} from 'clsx'
9
+
10
const FALLBACK = `http://_${Math.random().toString().slice(2)}._${Math.random().toString().slice(2)}`
11
12
const getLocalPath = href => {
@@ -26,34 +30,27 @@ const GatsbyLinkWithoutSxProps = React.forwardRef(function GatsbyLinkWithoutSxPr
30
return <GatsbyLink ref={ref} {...omit(props, 'sx', 'underline', 'hoverColor', 'muted')} />
31
})
32
29
-const Link = React.forwardRef(function Link({to, href, showUnderline = false, sx, ...props}, ref) {
33
+const Link = React.forwardRef(function Link({to, href, showUnderline = false, className, ...props}, ref) {
34
const localPath = getLocalPath(href)
31
-
32
- const linkStyles = {
33
- ...sx,
34
- ...(showUnderline && {textDecoration: 'underline'}),
35
- }
35
+ const combinedClassName = showUnderline ? clsx(className, styles.showUnderline) : className
36
37
if (to || localPath !== null) {
38
- return <PrimerLink ref={ref} as={GatsbyLinkWithoutSxProps} to={to || localPath} sx={linkStyles} {...props} />
38
+ return (
39
+ <PrimerLink
40
+ ref={ref}
41
+ as={GatsbyLinkWithoutSxProps}
42
+ to={to || localPath}
43
+ className={combinedClassName}
44
+ {...props}
45
+ />
46
+ )
47
}
48
41
- return <PrimerLink ref={ref} href={href} sx={linkStyles} {...props} />
49
+ return <PrimerLink ref={ref} href={href} className={combinedClassName} {...props} />
50
})
51
44
-export const LinkNoUnderline = React.forwardRef(function LinkNoUnderline({sx, ...props}, ref) {
45
- return (
46
- <Link
47
- ref={ref}
48
- sx={{
49
- ...sx,
50
- '&:hover, &:focus': {
51
- textDecoration: 'none',
52
- },
53
- }}
54
- {...props}
55
- />
56
- )
52
+export const LinkNoUnderline = React.forwardRef(function LinkNoUnderline({className, ...props}, ref) {
53
+ return <Link ref={ref} className={clsx(styles.Link, className)} {...props} />
54
})
55
56
export default Link
src/components/link.module.css
new
+10
@@ -0,0 +1,10 @@
1
+.Link {
2
+ &:hover,
3
+ &:focus {
4
+ text-decoration: none;
5
+ }
6
+}
7
+
8
+.showUnderline {
9
+ text-decoration: underline;
10
+}
src/components/nav-drawer.js
+10
-60
@@ -9,6 +9,8 @@ import {FocusOn} from 'react-focus-on'
9
import {HEADER_BAR, HEADER_HEIGHT} from '../constants'
10
import SiteTitle from './site-title'
11
12
+import * as styles from './nav-drawer.module.css'
13
+
14
const Drawer = ({isOpen, onDismiss, children}) => (
15
<AnimatePresence>
16
{isOpen ? (
@@ -24,14 +26,6 @@ const Drawer = ({isOpen, onDismiss, children}) => (
26
>
27
<FocusOn returnFocus={true} onEscapeKey={onDismiss}>
28
<Box
27
- sx={{
28
- position: 'fixed',
29
- top: 0,
30
- right: 0,
31
- bottom: 0,
32
- left: 0,
33
- bg: 'overlay.backdrop',
34
- }}
29
key="overlay"
30
as={motion.div}
31
initial={{opacity: 0}}
@@ -39,22 +33,17 @@ const Drawer = ({isOpen, onDismiss, children}) => (
33
exit={{opacity: 0}}
34
transition={{type: 'tween'}}
35
onClick={onDismiss}
36
+ className={styles.Box}
37
/>
38
<Box
44
- sx={{
45
- position: 'fixed',
46
- top: `${HEADER_BAR}px`,
47
- right: 0,
48
- bottom: 0,
49
- width: 300,
50
- zIndex: 1,
51
- }}
39
+ style={{top: `${HEADER_BAR}px`}}
40
key="drawer"
41
as={motion.div}
42
initial={{x: '100%'}}
43
animate={{x: 0}}
44
exit={{x: '100%'}}
45
transition={{type: 'tween', duration: 0.2}}
46
+ className={styles.Box_1}
47
>
48
{children}
49
</Box>
@@ -76,58 +65,19 @@ function NavDrawer() {
65
66
return (
67
<>
79
- <Button
80
- aria-label="Menu"
81
- aria-expanded={open}
82
- onClick={() => setOpen(true)}
83
- sx={{
84
- ml: 3,
85
- '&:focus-visible': {
86
- outline: '2px solid',
87
- outlineColor: '-webkit-focus-ring-color',
88
- outlineOffset: '1px',
89
- },
90
- }}
91
- >
68
+ <Button aria-label="Menu" aria-expanded={open} onClick={() => setOpen(true)} className={styles.Button}>
69
<ThreeBarsIcon />
70
</Button>
71
<LightTheme as={Drawer} isOpen={open} onDismiss={() => setOpen(false)}>
95
- <Box
96
- sx={{
97
- display: 'flex',
98
- flexDirection: 'column',
99
- height: '100%',
100
- bg: 'canvas.backdrop',
101
- overflow: 'auto',
102
- }}
103
- style={{WebkitOverflowScrolling: 'touch'}}
104
- >
105
- <Box
106
- sx={{
107
- display: 'flex',
108
- flexDirection: 'column',
109
- flex: '1 0 auto',
110
- color: 'fg.default',
111
- bg: 'canvas.default',
112
- }}
113
- >
114
- <DarkTheme
115
- sx={{
116
- color: 'fg.default',
117
- bg: 'canvas.default',
118
- height: `${HEADER_HEIGHT}px`,
119
- px: 3,
120
- alignItems: 'center',
121
- justifyContent: 'space-between',
122
- display: 'flex',
123
- }}
124
- >
72
+ <Box style={{WebkitOverflowScrolling: 'touch'}} className={styles.Box_2}>
73
+ <Box className={styles.Box_3}>
74
+ <DarkTheme style={{height: `${HEADER_HEIGHT}px`}} className={styles.DarkTheme}>
75
<SiteTitle />
76
<Button aria-label="Close" onClick={() => setOpen(false)}>
77
<XIcon />
78
</Button>
79
</DarkTheme>
130
- <Box sx={{display: 'flex', flexDirection: 'column'}}>
80
+ <Box className={styles.Box_4}>
81
<NavItems />
82
</Box>
83
</Box>
src/components/nav-drawer.module.css
new
+57
@@ -0,0 +1,57 @@
1
+.Box {
2
+ position: fixed;
3
+ top: 0;
4
+ right: 0;
5
+ bottom: 0;
6
+ left: 0;
7
+ background: rgba(140, 149, 159, 0.15);
8
+}
9
+
10
+.Box_1 {
11
+ position: fixed;
12
+ right: 0;
13
+ bottom: 0;
14
+ width: 300px;
15
+ z-index: 1;
16
+}
17
+
18
+.Box_2 {
19
+ display: flex;
20
+ flex-direction: column;
21
+ height: 100%;
22
+ background: #333333;
23
+ overflow: auto;
24
+}
25
+
26
+.Box_3 {
27
+ display: flex;
28
+ flex-direction: column;
29
+ flex: 1 0 auto;
30
+ color: #e1e4e8;
31
+ background: #333333;
32
+}
33
+
34
+.Box_4 {
35
+ display: flex;
36
+ flex-direction: column;
37
+}
38
+
39
+.Button {
40
+ margin-left: 16px;
41
+}
42
+
43
+.Button:focus-visible {
44
+ outline: 2px solid;
45
+ outline-color: -webkit-focus-ring-color;
46
+ outline-offset: 1px;
47
+}
48
+
49
+.DarkTheme {
50
+ color: #e1e4e8;
51
+ background: #333333;
52
+ padding-left: 16px;
53
+ padding-right: 16px;
54
+ align-items: center;
55
+ justify-content: space-between;
56
+ display: flex;
57
+}
src/components/nav-items.js
+5
-3
@@ -8,6 +8,8 @@ import headerNavItems from '../../content/header-nav.yml'
8
import usePage from '../hooks/use-page'
9
import useSiteMetadata from '../hooks/use-site-metadata'
10
11
+import * as styles from './nav-items.module.css'
12
+
13
const NavItem = ({item, path, depth}) => {
14
const isCurrent = getNav.isActiveUrl(path, item.url)
15
const items = getNav.getHierarchy(item, item.url, {hideVariants: true})
@@ -18,7 +20,7 @@ const NavItem = ({item, path, depth}) => {
20
to={item.url}
21
defaultOpen={items && isCurrent}
22
aria-current={isCurrent ? 'page' : null}
21
- sx={{fontSize: depth === 1 ? 2 : 1}}
23
+ className={depth === 1 ? styles.NavList_Item_depth1 : styles.NavList_Item_depth2}
24
>
25
{item.title}
26
{items ? (
@@ -43,7 +45,7 @@ const NavItems = ({items, path, depth = 1}) => (
45
)
46
47
const ExternalNavItem = ({title, ...props}) => (
46
- <NavList.Item sx={{fontSize: 2}} {...props}>
48
+ <NavList.Item className={styles.NavList_Item} {...props}>
49
{title}
50
<NavList.TrailingVisual>
51
<LinkExternalIcon />
@@ -63,7 +65,7 @@ const Navigation = () => {
65
<NavItems items={items} path={pathname} />
66
<NavList.Divider />
67
{headerNavItems.map(item => (
66
- <Box key={item.title} sx={{display: ['flex', null, null, 'none']}}>
68
+ <Box key={item.title} className={styles.headerNavItem}>
69
<ExternalNavItem title={item.title} href={item.url} />
70
</Box>
71
))}
src/components/nav-items.module.css
new
+21
@@ -0,0 +1,21 @@
1
+.NavList_Item {
2
+ font-size: 16px;
3
+}
4
+
5
+.NavList_Item_depth1 {
6
+ font-size: 16px;
7
+}
8
+
9
+.NavList_Item_depth2 {
10
+ font-size: 14px;
11
+}
12
+
13
+.headerNavItem {
14
+ display: flex;
15
+}
16
+
17
+@media (min-width: 1012px) {
18
+ .headerNavItem {
19
+ display: none;
20
+ }
21
+}
src/components/page-footer.js
+9
-17
@@ -6,6 +6,8 @@ import {PencilIcon} from '@primer/octicons-react'
6
import Link from './link'
7
import usePage from '../hooks/use-page'
8
9
+import * as styles from './page-footer.module.css'
10
+
11
const months = [
12
'January',
13
'February',
@@ -32,20 +34,20 @@ const Contributors = ({contributors = [], latestCommit}) => {
34
35
return (
36
<>
35
- <Box sx={{display: 'flex', alignItems: 'center', flexWrap: 'wrap'}}>
36
- <Text sx={{mr: 2}}>
37
+ <Box className={styles.Box}>
38
+ <Text className={styles.Text}>
39
{contributors.length} {pluralize('contributor', contributors.length)}
40
</Text>
41
{contributors.map(login => (
42
<Tooltip key={login} text={login}>
41
- <Link href={`https://github.com/${login}`} sx={{lineHeight: 'condensedUltra', mr: 2}}>
43
+ <Link href={`https://github.com/${login}`} className={styles.Link}>
44
<Avatar src={`https://github.com/${login}.png?size=40`} alt={login} />
45
</Link>
46
</Tooltip>
47
))}
48
</Box>
49
{latestCommit ? (
48
- <Text sx={{fontSize: 1, mt: 1}}>
50
+ <Text className={styles.Text_1}>
51
Last edited by{' '}
52
<Link href={`https://github.com/${latestCommit.login}`} showUnderline={true}>
53
{latestCommit.login}
@@ -68,21 +70,11 @@ const PageFooter = () => {
70
}
71
72
return (
71
- <Box
72
- sx={{
73
- borderWidth: 0,
74
- borderTopWidth: 1,
75
- borderRadius: 0,
76
- mt: 8,
77
- py: 5,
78
- borderStyle: 'solid',
79
- borderColor: 'border.default',
80
- }}
81
- >
82
- <Box sx={{display: 'grid', gap: 4}}>
73
+ <Box className={styles.Box_1}>
74
+ <Box className={styles.Box_2}>
75
{editUrl ? (
76
<Link href={editUrl}>
85
- <Octicon icon={PencilIcon} sx={{mr: 2}} />
77
+ <Octicon icon={PencilIcon} className={styles.Text} />
78
Edit this page on GitHub
79
</Link>
80
) : null}
src/components/page-footer.module.css
new
+35
@@ -0,0 +1,35 @@
1
+.Box {
2
+ display: flex;
3
+ align-items: center;
4
+ flex-wrap: wrap;
5
+}
6
+
7
+.Box_1 {
8
+ border-width: 0;
9
+ border-top-width: 1px;
10
+ border-radius: 0;
11
+ margin-top: 64px;
12
+ padding-top: 32px;
13
+ padding-bottom: 32px;
14
+ border-style: solid;
15
+ border-color: #444d56;
16
+}
17
+
18
+.Box_2 {
19
+ display: grid;
20
+ gap: 16px;
21
+}
22
+
23
+.Text {
24
+ margin-right: 8px;
25
+}
26
+
27
+.Link {
28
+ line-height: 1.25;
29
+ margin-right: 8px;
30
+}
31
+
32
+.Text_1 {
33
+ font-size: 14px;
34
+ margin-top: 4px;
35
+}
src/components/search.js
+26
-84
@@ -12,12 +12,14 @@ import * as getNav from '../util/get-nav'
12
import omit from '../util/omit'
13
import {announce} from '../util/aria-live'
14
15
+import * as styles from './search.module.css'
16
+
17
const SearchResults = ({results, getItemProps, highlightedIndex}) => {
18
const siteMetadata = useSiteMetadata()
19
if (!results || results.length === 0) {
20
announce('No results')
21
return (
20
- <Box sx={{fontSize: 2, px: 3, py: 3}} aria-live="polite">
22
+ <Box aria-live="polite" className={styles.Box}>
23
No results
24
</Box>
25
)
@@ -46,10 +48,10 @@ const SearchResults = ({results, getItemProps, highlightedIndex}) => {
48
active={highlightedIndex === index}
49
>
50
<Box
49
- sx={{display: 'flex', flexDirection: 'column', flex: '0 0 auto'}}
51
aria-label={`${item.title}${hierarchy.length ? ` in ${hierarchy.map(s => s.shortName || s.title).join(' / ')}` : ` in ${siteMetadata.shortName}`}, ${index + 1} of ${results.length}`}
52
+ className={styles.Box_1}
53
>
52
- <Text sx={{fontSize: 0}}>
54
+ <Text className={styles.Text}>
55
{hierarchy.length ? hierarchy.map(s => s.shortName || s.title).join(' / ') : siteMetadata.shortName}
56
</Text>
57
<Text>{item.title}</Text>
@@ -66,28 +68,16 @@ export const Desktop = props => {
68
const {getInputProps, getMenuProps, resultsOpen, ...rest} = props
69
70
return (
69
- <Box sx={{position: 'relative'}}>
71
+ <Box className={styles.Box_2}>
72
<TextInput
71
- sx={{width: '240px'}}
73
placeholder={`Search ${siteMetadata.title}`}
74
aria-label={`Search ${siteMetadata.title}`}
75
+ className={styles.TextInput}
76
{...getInputProps()}
77
/>
76
- <Box sx={{position: 'absolute', left: 0, right: 0, pt: 1}} {...getMenuProps()}>
78
+ <Box className={styles.Box_3} {...getMenuProps()}>
79
{resultsOpen ? (
78
- <LightTheme
79
- sx={{
80
- overflow: 'auto',
81
- minWidth: 300,
82
- maxHeight: '70vh',
83
- boxShadow: 'shadow.large',
84
- borderColor: 'border.muted',
85
- bg: 'canvas.overlay',
86
- borderRadius: 2,
87
- borderWidth: 1,
88
- borderStyle: 'solid',
89
- }}
90
- >
80
+ <LightTheme className={styles.LightTheme}>
81
<SearchResults {...rest} />
82
</LightTheme>
83
) : null}
@@ -120,67 +110,43 @@ export const Mobile = ({
110
aria-label="Search"
111
aria-expanded={isMobileSearchOpen}
112
onClick={handleSearchToggle}
123
- sx={{
124
- '&:focus-visible': {
125
- outline: '2px solid',
126
- outlineColor: '-webkit-focus-ring-color',
127
- outlineOffset: '1px',
128
- },
129
- }}
113
+ className={styles.Button}
114
>
115
<SearchIcon />
116
</Button>
117
)}
134
-
118
<AnimatePresence>
119
{isMobileSearchOpen ? (
120
<FocusOn returnFocus={true} onEscapeKey={() => resetAndClose(true)}>
121
<Box
139
- sx={{
140
- position: 'fixed',
122
+ style={{
123
top: `${HEADER_BAR}px`,
142
- left: 0,
143
- right: 0,
144
- bottom: 0,
124
zIndex: Z_INDEX.SEARCH_OVERLAY,
125
}}
126
+ className={styles.Box_4}
127
>
128
<Box
149
- sx={{
150
- position: 'absolute',
151
- top: 0,
152
- left: 0,
153
- right: 0,
154
- bottom: 0,
155
- bg: 'overlay.backdrop',
156
- zIndex: -1,
157
- }}
129
key="search-backdrop"
130
as={motion.div}
131
initial={{opacity: 0}}
132
animate={{opacity: 1}}
133
transition={{type: 'tween'}}
134
onClick={() => resetAndClose(true)}
135
+ className={styles.Box_5}
136
{...getCloseAnimation({opacity: 0})}
137
/>
166
- <Box sx={{display: 'flex', flexDirection: 'column', height: resultsOpen ? '100%' : 'auto'}}>
138
+ <Box
139
+ style={{
140
+ height: resultsOpen ? '100%' : 'auto',
141
+ }}
142
+ className={styles.Box_6}
143
+ >
144
<Box
168
- sx={{
169
- display: 'flex',
170
- color: 'fg.default',
145
+ style={{
146
height: `${HEADER_HEIGHT}px`,
172
- flex: '0 0 auto',
173
- px: 3,
174
- alignItems: 'center',
175
- border: '1px solid',
176
- borderTopWidth: 0,
177
- borderLeftWidth: 0,
178
- borderRightWidth: 0,
179
- borderColor: 'border.muted',
180
- position: 'relative',
181
- bg: 'canvas.default',
147
zIndex: Z_INDEX.SEARCH_OVERLAY + 1,
148
}}
149
+ className={styles.Box_7}
150
>
151
<motion.div
152
key="search-box"
@@ -190,22 +156,12 @@ export const Mobile = ({
156
transition={{type: 'tween', ease: 'easeOut', duration: 0.2}}
157
style={{width: '100%', originX: '100%'}}
158
>
193
- <Box
194
- sx={{
195
- position: 'absolute',
196
- top: 0,
197
- bottom: 0,
198
- left: 0,
199
- width: '70px',
200
- bg: 'canvas.default',
201
- zIndex: '-1',
202
- }}
203
- />
159
+ <Box className={styles.Box_8} />
160
<TextInput
161
leadingVisual={SearchIcon}
162
placeholder={`Search ${siteMetadata.title}`}
163
aria-label={`Search ${siteMetadata.title}`}
208
- sx={{width: '100%'}}
164
+ className={styles.TextInput_1}
165
{...getInputProps()}
166
/>
167
</motion.div>
@@ -216,15 +172,7 @@ export const Mobile = ({
172
animate={{opacity: 1}}
173
{...getCloseAnimation({scaleX: 0})}
174
transition={{type: 'tween', ease: 'easeOut', duration: 0.2}}
219
- sx={{
220
- position: 'absolute',
221
- top: 0,
222
- bottom: 0,
223
- right: 0,
224
- width: '70px',
225
- bg: 'canvas.default',
226
- zIndex: '-1',
227
- }}
175
+ className={styles.Box_9}
176
/>
177
<Box
178
key="button"
@@ -234,22 +182,16 @@ export const Mobile = ({
182
{...getCloseAnimation({opacity: 0})}
183
transition={{type: 'tween', ease: 'easeOut', duration: 0.2}}
184
>
237
- <Button sx={{ml: 3}} aria-label="Cancel" onClick={() => resetAndClose(false)}>
185
+ <Button aria-label="Cancel" onClick={() => resetAndClose(false)} className={styles.Button_1}>
186
<XIcon />
187
</Button>
188
</Box>
189
</Box>
190
<LightTheme
243
- sx={{
244
- display: 'flex',
245
- bg: 'canvas.default',
246
- flexDirection: 'column',
247
- flex: '1 1 auto',
248
- overflow: 'auto',
249
- }}
191
style={{
192
WebkitOverflowScrolling: 'touch',
193
}}
194
+ className={styles.LightTheme_1}
195
{...getMenuProps()}
196
>
197
{resultsOpen ? <SearchResults {...rest} /> : null}
src/components/search.module.css
new
+121
@@ -0,0 +1,121 @@
1
+.Box {
2
+ font-size: 16px;
3
+ padding: 16px;
4
+}
5
+
6
+.Box_1 {
7
+ display: flex;
8
+ flex-direction: column;
9
+ flex: 0 0 auto;
10
+}
11
+
12
+.Box_2 {
13
+ position: relative;
14
+}
15
+
16
+.Box_3 {
17
+ position: absolute;
18
+ left: 0;
19
+ right: 0;
20
+ padding-top: 4px;
21
+}
22
+
23
+.Box_4 {
24
+ position: fixed;
25
+ left: 0;
26
+ right: 0;
27
+ bottom: 0;
28
+}
29
+
30
+.Box_5 {
31
+ position: absolute;
32
+ top: 0;
33
+ left: 0;
34
+ right: 0;
35
+ bottom: 0;
36
+ background: rgba(140, 149, 159, 0.15);
37
+ z-index: -1;
38
+}
39
+
40
+.Box_6 {
41
+ display: flex;
42
+ flex-direction: column;
43
+}
44
+
45
+.Box_7 {
46
+ display: flex;
47
+ color: #1f2328;
48
+ flex: 0 0 auto;
49
+ padding-left: 16px;
50
+ padding-right: 16px;
51
+ align-items: center;
52
+ border: 1px solid;
53
+ border-top-width: 0;
54
+ border-left-width: 0;
55
+ border-right-width: 0;
56
+ border-color: #d0d7de;
57
+ position: relative;
58
+ background: #ffffff;
59
+}
60
+
61
+.Box_8 {
62
+ position: absolute;
63
+ top: 0;
64
+ bottom: 0;
65
+ left: 0;
66
+ width: 70px;
67
+ background: #ffffff;
68
+ z-index: -1;
69
+}
70
+
71
+.Box_9 {
72
+ position: absolute;
73
+ top: 0;
74
+ bottom: 0;
75
+ right: 0;
76
+ width: 70px;
77
+ background: #ffffff;
78
+ z-index: -1;
79
+}
80
+
81
+.Text {
82
+ font-size: 12px;
83
+}
84
+
85
+.TextInput {
86
+ width: 240px;
87
+}
88
+
89
+.LightTheme {
90
+ overflow: auto;
91
+ min-width: 300px;
92
+ max-height: 70vh;
93
+ box-shadow: 0 8px 24px rgba(140, 149, 159, 0.2);
94
+ border-color: #d0d7de;
95
+ background: #ffffff;
96
+ border-radius: 6px;
97
+ border-width: 1px;
98
+ border-style: solid;
99
+}
100
+
101
+.Button:focus-visible {
102
+ outline: 2px solid;
103
+ outline-color: -webkit-focus-ring-color;
104
+ outline-offset: 1px;
105
+}
106
+
107
+.TextInput_1 {
108
+ width: 100%;
109
+}
110
+
111
+.Button_1 {
112
+ margin-left: 16px;
113
+}
114
+
115
+.LightTheme_1 {
116
+ display: flex;
117
+ background: #ffffff;
118
+ flex-direction: column;
119
+ flex: 1 1 auto;
120
+ overflow: auto;
121
+}
src/components/sidebar.js
+6
-15
@@ -3,6 +3,8 @@ import React from 'react'
3
import NavItems from './nav-items'
4
import {FULL_HEADER_HEIGHT} from '../constants'
5
6
+import * as styles from './sidebar.module.css'
7
+
8
function usePersistentScroll(id) {
9
const ref = React.useRef()
10
@@ -30,25 +32,14 @@ function usePersistentScroll(id) {
32
const Sidebar = () => (
33
<Box
34
role="navigation"
33
- sx={{
34
- position: 'sticky',
35
+ style={{
36
top: `${FULL_HEADER_HEIGHT}px`,
37
height: `calc(100vh - ${FULL_HEADER_HEIGHT}px)`,
37
- width: 270,
38
}}
39
+ className={styles.Box}
40
>
40
- <Box
41
- {...usePersistentScroll('sidebar')}
42
- sx={{
43
- overflow: 'auto',
44
- borderWidth: 0,
45
- borderRightWidth: 1,
46
- height: '100%',
47
- borderStyle: 'solid',
48
- borderColor: 'border.subtle',
49
- }}
50
- >
51
- <Box sx={{display: 'flex', flexDirection: 'column'}}>
41
+ <Box {...usePersistentScroll('sidebar')} className={styles.Box_1}>
42
+ <Box className={styles.Box_2}>
43
<NavItems />
44
</Box>
45
</Box>
src/components/sidebar.module.css
new
+18
@@ -0,0 +1,18 @@
1
+.Box {
2
+ position: sticky;
3
+ width: 270px;
4
+}
5
+
6
+.Box_1 {
7
+ overflow: auto;
8
+ border-width: 0;
9
+ border-right-width: 1px;
10
+ height: 100%;
11
+ border-style: solid;
12
+ border-color: #444d56;
13
+}
14
+
15
+.Box_2 {
16
+ display: flex;
17
+ flex-direction: column;
18
+}
src/components/site-title.js
+8
-15
@@ -3,8 +3,11 @@ import {Box} from '@primer/react'
3
import Link from './link'
4
import useSiteMetadata from '../hooks/use-site-metadata'
5
6
-const NpmLogo = ({size, sx}) => (
7
- <Box sx={{...sx, color: 'logoBg'}}>
6
+import * as styles from './site-title.module.css'
7
+import {clsx} from 'clsx'
8
+
9
+const NpmLogo = ({size, className}) => (
10
+ <Box className={clsx(styles.Box, className)}>
11
<svg height={size} width={size} viewBox="0 0 700 700" fill="currentColor" aria-hidden="true">
12
<polygon fill="currentColor" points="0,700 700,700 700,0 0,0" />
13
<polygon fill="#ffffff" points="150,550 350,550 350,250 450,250 450,550 550,550 550,150 150,150 " />
@@ -12,22 +15,12 @@ const NpmLogo = ({size, sx}) => (
15
</Box>
16
)
17
15
-const SiteTitle = ({logo, sx}) => {
18
+const SiteTitle = ({logo, className}) => {
19
const siteMetadata = useSiteMetadata()
20
21
return (
19
- <Link
20
- to="/"
21
- sx={{
22
- fontWeight: 'bold',
23
- fontSize: 2,
24
- color: 'fg.default',
25
- display: 'flex',
26
- alignItems: 'center',
27
- ...sx,
28
- }}
29
- >
30
- {logo ? <NpmLogo size="32" sx={{display: 'flex', mr: 3}} /> : null}
22
+ <Link to="/" className={clsx(styles.Link, className)}>
23
+ {logo ? <NpmLogo size="32" className={styles.NpmLogo} /> : null}
24
{siteMetadata.title}
25
</Link>
26
)
src/components/site-title.module.css
new
+16
@@ -0,0 +1,16 @@
1
+.Box {
2
+ color: #cb3837;
3
+}
4
+
5
+.Link {
6
+ font-weight: bold;
7
+ font-size: 16px;
8
+ color: #e1e4e8;
9
+ display: flex;
10
+ align-items: center;
11
+}
12
+
13
+.NpmLogo {
14
+ display: flex;
15
+ margin-right: 16px;
16
+}
src/components/table-of-contents.js
+12
-53
@@ -1,9 +1,11 @@
1
import React from 'react'
2
import {Heading, Box, Details, useDetails, Button, NavList} from '@primer/react'
3
import {ChevronDownIcon, ChevronRightIcon} from '@primer/octicons-react'
4
-import {SCROLL_MARGIN_TOP} from '../constants'
4
import usePage from '../hooks/use-page'
5
6
+import * as styles from './table-of-contents.module.css'
7
+import {clsx} from 'clsx'
8
+
9
const TableOfContentsItems = ({items, depth}) => (
10
<>
11
{items.map((item, index) => (
@@ -25,15 +27,8 @@ const TableOfContentsItems = ({items, depth}) => (
27
</>
28
)
29
28
-const TableOfContents = ({'aria-labelledby': ariaLabelledBy, items, depth = 1, ...props}) => (
29
- <NavList
30
- aria-labelledby={ariaLabelledBy}
31
- {...props}
32
- sx={{
33
- textDecoration: 'underline',
34
- ...props.sx,
35
- }}
36
- >
30
+const TableOfContents = ({'aria-labelledby': ariaLabelledBy, items, depth = 1, className, ...props}) => (
31
+ <NavList aria-labelledby={ariaLabelledBy} {...props} className={clsx(styles.NavList, className)}>
32
<TableOfContentsItems items={items} depth={depth} />
33
</NavList>
34
)
@@ -49,32 +44,12 @@ const withTableOfContents = Component => {
44
export const Mobile = withTableOfContents(({items}) => {
45
const {getDetailsProps, open} = useDetails({defaultOpen: true})
46
return (
52
- <Box sx={{display: ['block', null, 'none'], mb: 3, mt: 4}}>
53
- <Details
54
- {...getDetailsProps()}
55
- sx={{
56
- borderStyle: 'solid',
57
- borderWidth: 1,
58
- borderColor: 'border.muted',
59
- borderRadius: 2,
60
- }}
61
- >
47
+ <Box className={styles.tocMobile}>
48
+ <Details {...getDetailsProps()} className={styles.Details}>
49
<Button
50
as="summary"
64
- sx={{
65
- borderTopWidth: 0,
66
- borderLeftWidth: 0,
67
- borderRightWidth: 0,
68
- borderBottomWidth: open ? 1 : 0,
69
- borderBottomLeftRadius: open ? 0 : 2,
70
- borderBottomRightRadius: open ? 0 : 2,
71
- '&:focus-visible': {
72
- outline: '2px solid',
73
- outlineColor: '-webkit-focus-ring-color',
74
- outlineOffset: '1px',
75
- },
76
- }}
51
leadingIcon={open ? ChevronDownIcon : ChevronRightIcon}
52
+ className={`${styles.Button} ${open ? styles.buttonOpen : styles.buttonClosed}`}
53
>
54
Table of contents
55
</Button>
@@ -85,28 +60,12 @@ export const Mobile = withTableOfContents(({items}) => {
60
})
61
62
export const Desktop = withTableOfContents(({items}) => (
88
- <Box
89
- sx={{
90
- width: 220,
91
- flex: '0 0 auto',
92
- marginLeft: [null, 7, 8, 9],
93
- display: ['none', null, 'block'],
94
- position: 'sticky',
95
- top: SCROLL_MARGIN_TOP,
96
- maxHeight: `calc(100vh - ${SCROLL_MARGIN_TOP}px)`,
97
- }}
98
- >
99
- <Heading as="h2" sx={{fontSize: 1, display: 'inline-block', fontWeight: 'bold'}} id="toc-heading">
63
+ <Box className={styles.tocDesktop}>
64
+ <Heading as="h2" id="toc-heading" className={styles.Heading}>
65
Table of contents
66
</Heading>
102
- <Box
103
- sx={{
104
- // extra pixels to account for table of contents title height
105
- maxHeight: `calc(100% - 24px)`,
106
- overflowY: 'auto',
107
- }}
108
- >
109
- <TableOfContents aria-labelledby="toc-heading" items={items} sx={{ml: -2}} />
67
+ <Box className={styles.Box}>
68
+ <TableOfContents aria-labelledby="toc-heading" items={items} className={styles.TableOfContents} />
69
</Box>
70
</Box>
71
))
src/components/table-of-contents.module.css
new
+97
@@ -0,0 +1,97 @@
1
+.Box {
2
+ overflow-y: auto;
3
+ /* extra pixels to account for table of contents title height */
4
+ max-height: calc(100% - 24px);
5
+}
6
+
7
+.NavList {
8
+ text-decoration: underline;
9
+}
10
+
11
+/* borderRadius: 2 = 6px */
12
+.Details {
13
+ border-style: solid;
14
+ border-width: 1px;
15
+ border-color: #444d56;
16
+ border-radius: 6px;
17
+}
18
+
19
+.Button {
20
+ border-top-width: 0;
21
+ border-left-width: 0;
22
+ border-right-width: 0;
23
+}
24
+
25
+.Button:focus-visible {
26
+ outline: 2px solid;
27
+ outline-color: -webkit-focus-ring-color;
28
+ outline-offset: 1px;
29
+}
30
+
31
+.buttonOpen {
32
+ border-bottom-width: 1px;
33
+ border-bottom-left-radius: 0;
34
+ border-bottom-right-radius: 0;
35
+}
36
+
37
+/* borderRadius: 2 = 6px, but since 0 border, it's effectively a smaller radius for consistency */
38
+.buttonClosed {
39
+ border-bottom-width: 0;
40
+ border-bottom-left-radius: 6px;
41
+ border-bottom-right-radius: 6px;
42
+}
43
+
44
+/* fontSize: 1 = 14px */
45
+.Heading {
46
+ font-size: 14px;
47
+ display: inline-block;
48
+ font-weight: bold;
49
+}
50
+
51
+/* ml: -2 = -8px */
52
+.TableOfContents {
53
+ margin-left: -8px;
54
+}
55
+
56
+/* mb: 3 = 16px, mt: 4 = 24px */
57
+.tocMobile {
58
+ display: block;
59
+ margin-bottom: 16px;
60
+ margin-top: 24px;
61
+}
62
+
63
+@media (min-width: 768px) {
64
+ .tocMobile {
65
+ display: none;
66
+ }
67
+}
68
+
69
+/* marginLeft: [null, 7, 8, 9] = 48px, 64px, 80px */
70
+.tocDesktop {
71
+ width: 220px;
72
+ flex: 0 0 auto;
73
+ margin-left: 48px;
74
+ display: none;
75
+ position: sticky;
76
+ top: 90px;
77
+ max-height: calc(100vh - 90px);
78
+}
79
+
80
+@media (min-width: 544px) {
81
+ .tocDesktop {
82
+ margin-left: 48px;
83
+ }
84
+}
85
+
86
+@media (min-width: 768px) {
87
+ .tocDesktop {
88
+ display: block;
89
+ margin-left: 64px;
90
+ }
91
+}
92
+
93
+@media (min-width: 1012px) {
94
+ .tocDesktop {
95
+ margin-left: 80px;
96
+ }
97
+}
src/components/variant-select.js
+6
-13
@@ -6,6 +6,8 @@ import {LinkNoUnderline} from './link'
6
import useLocationChange from '../hooks/use-location-change'
7
import styled from 'styled-components'
8
9
+import * as styles from './variant-select.module.css'
10
+
11
const StyledOverlay = styled(ActionMenu.Overlay)`
12
background-color: var(--bgColor-default, #ffffff) !important;
13
border-color: var(--borderColor-default, #d0d7de);
@@ -45,25 +47,16 @@ const VariantMenu = ({title, latest, current, prerelease, legacy}) => {
47
if (locationChange.change && getNav.didVariantChange(locationChange.previous, locationChange.current)) {
48
setOpen(false)
49
}
50
+ // eslint-disable-next-line react-hooks/exhaustive-deps -- granular deps are intentional; locationChange.current is a URL string, not a ref
51
}, [locationChange.change, locationChange.current, locationChange.previous])
52
53
return (
54
<>
52
- <Box as="p" sx={{m: 0}} id={labelId}>
55
+ <Box as="p" id={labelId} className={styles.Box}>
56
Select CLI Version:
57
</Box>
58
<ActionMenu anchorRef={anchorRef} open={open} onOpenChange={setOpen}>
56
- <ActionMenu.Button
57
- aria-describedby={labelId}
58
- sx={{
59
- width: ['100%', null, 'auto'],
60
- '&:focus-visible': {
61
- outline: '2px solid',
62
- outlineColor: '-webkit-focus-ring-color',
63
- outlineOffset: '1px',
64
- },
65
- }}
66
- >
59
+ <ActionMenu.Button aria-describedby={labelId} className={styles.menuButton}>
60
{title}
61
</ActionMenu.Button>
62
<StyledOverlay width="auto" onEscape={() => setOpen(false)}>
@@ -133,7 +126,7 @@ const useVariants = () => {
126
const VariantSelect = () => {
127
const variants = useVariants()
128
return variants ? (
136
- <Box sx={{mt: 2, mb: 3}}>
129
+ <Box className={styles.Box_1}>
130
<VariantMenu {...variants} />
131
</Box>
132
) : null
src/components/variant-select.module.css
new
+24
@@ -0,0 +1,24 @@
1
+.Box {
2
+ margin: 0;
3
+}
4
+
5
+.Box_1 {
6
+ margin-top: 8px;
7
+ margin-bottom: 16px;
8
+}
9
+
10
+.menuButton {
11
+ width: 100%;
12
+}
13
+
14
+.menuButton:focus-visible {
15
+ outline: 2px solid;
16
+ outline-color: -webkit-focus-ring-color;
17
+ outline-offset: 1px;
18
+}
19
+
20
+@media (min-width: 768px) {
21
+ .menuButton {
22
+ width: auto;
23
+ }
24
+}
src/layout.js
+13
-19
@@ -10,25 +10,28 @@ import usePage from './hooks/use-page'
10
import {DarkTheme} from './theme'
11
import {SkipNav} from './components/skip-nav'
12
13
-const Container = ({sx, ...props}) => <Box sx={{width: '100%', maxWidth: '960px', ...sx}} {...props} />
13
+import * as styles from './layout.module.css'
14
+import {clsx} from 'clsx'
15
+
16
+const Container = ({className, ...props}) => <Box className={clsx(styles.Box, className)} {...props} />
17
18
const HeroLayout = ({children}) => {
19
const {title, description} = useSiteMetadata()
20
21
return (
19
- <Box as="main" sx={{width: '100%'}}>
20
- <DarkTheme sx={{bg: 'canvas.inset', py: [0, 4, 5, 6]}}>
21
- <Container sx={{p: 5, mx: 'auto'}}>
22
- <Heading as="h1" sx={{color: 'fg.default', fontSize: 7, m: 0}}>
22
+ <Box as="main" className={styles.Box_1}>
23
+ <DarkTheme className={styles.DarkTheme}>
24
+ <Container className={styles.Container}>
25
+ <Heading as="h1" className={styles.Heading}>
26
{title}
27
</Heading>
25
- <Text as="p" sx={{m: 0, color: 'fg.onEmphasis', fontSize: 4}}>
28
+ <Text as="p" className={styles.Text}>
29
{description}
30
</Text>
31
</Container>
32
</DarkTheme>
33
<SkipNav />
31
- <Container sx={{p: 5, mx: 'auto'}}>{children}</Container>
34
+ <Container className={styles.Container}>{children}</Container>
35
</Box>
36
)
37
}
@@ -36,21 +39,12 @@ const HeroLayout = ({children}) => {
39
const DefaultLayout = ({children}) => {
40
const {title, description} = usePage().frontmatter
41
return (
39
- <Box
40
- sx={{
41
- justifyContent: 'center',
42
- display: 'flex',
43
- maxWidth: '1200px',
44
- mx: 'auto',
45
- width: '100%',
46
- p: [4, 5, 6, 7],
47
- }}
48
- >
42
+ <Box className={styles.Box_2}>
43
<Container as="main">
50
- <Box sx={{mb: 4}}>
44
+ <Box className={styles.Box_3}>
45
<Breadcrumbs />
46
<H1 autolink={false}>{title}</H1>
53
- {description ? <Box sx={{fontSize: 3, mb: 3}}>{description}</Box> : null}
47
+ {description ? <Box className={styles.Box_4}>{description}</Box> : null}
48
</Box>
49
<SkipNav />
50
<VariantSelect />
src/layout.module.css
new
+98
@@ -0,0 +1,98 @@
1
+.Box {
2
+ width: 100%;
3
+ max-width: 960px;
4
+}
5
+
6
+.Box_1 {
7
+ width: 100%;
8
+}
9
+
10
+/* DefaultLayout wrapper - p: [4, 5, 6, 7] = 24px, 32px, 40px, 48px */
11
+.Box_2 {
12
+ justify-content: center;
13
+ display: flex;
14
+ max-width: 1200px;
15
+ margin-left: auto;
16
+ margin-right: auto;
17
+ width: 100%;
18
+ padding: 24px;
19
+}
20
+
21
+@media (min-width: 544px) {
22
+ .Box_2 {
23
+ padding: 32px;
24
+ }
25
+}
26
+
27
+@media (min-width: 768px) {
28
+ .Box_2 {
29
+ padding: 40px;
30
+ }
31
+}
32
+
33
+@media (min-width: 1012px) {
34
+ .Box_2 {
35
+ padding: 48px;
36
+ }
37
+}
38
+
39
+/* mb: 4 = 24px */
40
+.Box_3 {
41
+ margin-bottom: 24px;
42
+}
43
+
44
+/* fontSize: 3 = 20px, mb: 3 = 16px */
45
+.Box_4 {
46
+ font-size: 20px;
47
+ margin-bottom: 16px;
48
+}
49
+
50
+/* bg: 'canvas.inset', py: [0, 4, 5, 6] = 0, 24px, 32px, 40px */
51
+/* canvas.inset in dark mode - slightly darker than #333333 */
52
+.DarkTheme {
53
+ background-color: #292929;
54
+ padding-top: 0;
55
+ padding-bottom: 0;
56
+}
57
+
58
+@media (min-width: 544px) {
59
+ .DarkTheme {
60
+ padding-top: 24px;
61
+ padding-bottom: 24px;
62
+ }
63
+}
64
+
65
+@media (min-width: 768px) {
66
+ .DarkTheme {
67
+ padding-top: 32px;
68
+ padding-bottom: 32px;
69
+ }
70
+}
71
+
72
+@media (min-width: 1012px) {
73
+ .DarkTheme {
74
+ padding-top: 40px;
75
+ padding-bottom: 40px;
76
+ }
77
+}
78
+
79
+/* p: 5 = 32px, mx: auto */
80
+.Container {
81
+ padding: 32px;
82
+ margin-left: auto;
83
+ margin-right: auto;
84
+}
85
+
86
+/* color: 'fg.default' in dark_dimmed = #E1E4E8, fontSize: 7 = 48px, m: 0 */
87
+.Heading {
88
+ color: #e1e4e8;
89
+ font-size: 48px;
90
+ margin: 0;
91
+}
92
+
93
+/* m: 0, color: 'fg.onEmphasis' = white, fontSize: 4 = 24px */
94
+.Text {
95
+ margin: 0;
96
+ color: rgba(255, 255, 255, 0.9);
97
+ font-size: 24px;
98
+}
src/mdx/code.js
+11
-48
@@ -6,6 +6,8 @@ import styled from 'styled-components'
6
import {CheckIcon, CopyIcon} from '@primer/octicons-react'
7
import copyToClipboard from 'copy-to-clipboard'
8
import {announce} from '../util/aria-live'
9
+import * as styles from './code.module.css'
10
+import {clsx} from 'clsx'
11
;(typeof global !== 'undefined' ? global : window).Prism = Prism
12
require('prismjs/components/prism-bash')
13
@@ -24,23 +26,16 @@ const ClipboardCopy = ({value, ...props}) => {
26
27
return (
28
<Button
27
- {...props}
29
aria-label="Copy to clipboard"
30
+ size="small"
31
onClick={() => {
32
copyToClipboard(value)
33
setCopied(true)
34
announce(`Copied to clipboard`)
35
}}
34
- sx={{
35
- ...props.sx,
36
- '&:focus-visible': {
37
- outline: '2px solid',
38
- outlineColor: '-webkit-focus-ring-color',
39
- outlineOffset: '1px',
40
- },
41
- }}
36
+ className={clsx(styles.Button, props.className)}
37
>
43
- <Octicon icon={copied ? CheckIcon : CopyIcon} sx={{color: copied ? 'success.fg' : 'fg.muted'}} />
38
+ <Octicon icon={copied ? CheckIcon : CopyIcon} style={{color: copied ? '#1a7f37' : '#656d76'}} />
39
</Button>
40
)
41
}
@@ -60,46 +55,14 @@ const colorMap = {
55
'token string': '#db1068',
56
}
57
63
-const MonoText = props => <Text sx={{fontFamily: 'mono', fontSize: 1}} {...props} />
58
+const MonoText = props => <Text className={styles.Text} {...props} />
59
60
const CodeBlock = ({children, code, className, style}) => (
66
- <Box
67
- sx={{
68
- // Make <pre> adjust to the width of the container
69
- // https://stackoverflow.com/a/14406386
70
- display: 'table',
71
- tableLayout: 'fixed',
72
- width: '100%',
73
- mb: 3,
74
- }}
75
- >
76
- <Box
77
- style={style}
78
- sx={{
79
- ...(code ? {display: 'flex', justifyContent: 'space-between', flexDirection: 'row-reverse'} : {}),
80
- borderRadius: 2,
81
- borderStyle: 'solid',
82
- borderWidth: 1,
83
- borderColor: 'border.muted',
84
- }}
85
- >
86
- {code ? (
87
- <ClipboardCopy
88
- value={code}
89
- sx={{
90
- borderRadius: 0,
91
- borderStyle: 'solid',
92
- borderWidth: 1,
93
- borderColor: 'border.muted',
94
- marginTop: '-1px',
95
- marginRight: '-1px',
96
- borderTopRightRadius: 2,
97
- borderBottomLeftRadius: 2,
98
- }}
99
- />
100
- ) : null}
101
- <Box sx={{m: 0, p: 3, overflowX: 'auto'}}>
102
- <Box as="pre" className={className} tabIndex={0} sx={{m: 0}}>
61
+ <Box className={styles.Box}>
62
+ <Box style={style} className={styles.Box_1}>
63
+ {code ? <ClipboardCopy value={code} className={styles.ClipboardCopy} /> : null}
64
+ <Box className={styles.Box_2}>
65
+ <Box as="pre" className={clsx(className, styles.Box_3)} tabIndex={0}>
66
{children}
67
</Box>
68
</Box>
src/mdx/code.module.css
new
+60
@@ -0,0 +1,60 @@
1
+.Box {
2
+ display: table;
3
+ table-layout: fixed;
4
+ width: 100%;
5
+ margin-bottom: 16px;
6
+}
7
+
8
+.Box_1 {
9
+ position: relative;
10
+ border-radius: 6px;
11
+ border-style: solid;
12
+ border-width: 1px;
13
+ border-color: #d0d7de;
14
+}
15
+
16
+.Box_2 {
17
+ margin: 0;
18
+ padding: 16px;
19
+ overflow-x: auto;
20
+}
21
+
22
+.Box_3 {
23
+ margin: 0;
24
+}
25
+
26
+.Button {
27
+ position: absolute;
28
+ top: 0;
29
+ right: 0;
30
+}
31
+
32
+.Button:focus-visible {
33
+ outline: 2px solid;
34
+ outline-color: -webkit-focus-ring-color;
35
+ outline-offset: 1px;
36
+}
37
+
38
+.Text {
39
+ font-family:
40
+ ui-monospace,
41
+ SFMono-Regular,
42
+ SF Mono,
43
+ Menlo,
44
+ Consolas,
45
+ Liberation Mono,
46
+ monospace;
47
+ font-size: 14px;
48
+}
49
+
50
+.ClipboardCopy {
51
+ position: absolute;
52
+ top: -1px;
53
+ right: -1px;
54
+ border-radius: 0;
55
+ border-style: solid;
56
+ border-width: 1px;
57
+ border-color: #d0d7de;
58
+ border-top-right-radius: 6px;
59
+ border-bottom-left-radius: 6px;
60
+}
src/mdx/components.js
+7
-12
@@ -10,6 +10,10 @@ import usePage from '../hooks/use-page'
10
import SiteLink, {LinkNoUnderline} from '../components/link'
11
import Code from './code'
12
13
+import * as styles from './components.module.css'
14
+
15
+import {clsx} from 'clsx'
16
+
17
export {Code}
18
export {default as Index} from './nav-hierarchy'
19
@@ -42,18 +46,9 @@ const StyledHeading = styled(Heading)`
46
47
const HeaderLink = ({autolink, children, ...props}) =>
48
autolink ? (
45
- <LinkNoUnderline {...props} sx={{color: 'inherit'}}>
49
+ <LinkNoUnderline {...props} className={styles.LinkNoUnderline}>
50
{children}
47
- <Octicon
48
- icon={LinkIcon}
49
- className="octicon-link"
50
- sx={{
51
- ml: 2,
52
- color: 'fg.muted',
53
- // !important is needed here to override default icon styles
54
- verticalAlign: 'middle !important',
55
- }}
56
- />
51
+ <Octicon icon={LinkIcon} className={clsx('octicon-link', styles.Octicon)} />
52
</LinkNoUnderline>
53
) : (
54
children
@@ -304,10 +299,10 @@ export const Screenshot = styled(RequiredImage)`
299
export const YouTube = ({id}) => (
300
<Box
301
as="iframe"
307
- sx={{aspectRatio: '16 / 9', width: '100%'}}
302
title="YouTube video"
303
src={`https://www.youtube.com/embed/${id}`}
304
frameBorder="0"
305
allowFullScreen
306
+ className={styles.Box}
307
/>
308
)
src/mdx/components.module.css
new
+14
@@ -0,0 +1,14 @@
1
+.Box {
2
+ aspect-ratio: 16 / 9;
3
+ width: 100%;
4
+}
5
+
6
+.LinkNoUnderline {
7
+ color: inherit;
8
+}
9
+
10
+.Octicon {
11
+ margin-left: 8px;
12
+ color: #656d76;
13
+ vertical-align: middle !important;
14
+}
src/mdx/nav-hierarchy.js
+3
-1
@@ -4,6 +4,8 @@ import Link from '../components/link'
4
import * as getNav from '../util/get-nav'
5
import usePage from '../hooks/use-page'
6
7
+import * as styles from './nav-hierarchy.module.css'
8
+
9
const HierarchyItem = ({item, maxDepth, depth, hideVariants}) => {
10
const hierarchy = getNav.getHierarchy(item, null, {hideVariants})
11
@@ -12,7 +14,7 @@ const HierarchyItem = ({item, maxDepth, depth, hideVariants}) => {
14
<Link key={item.title} to={item.url}>
15
{item.title}
16
</Link>
15
- {item.description ? <Box sx={{fontSize: 1, mb: 1}}>{item.description}</Box> : null}
17
+ {item.description ? <Box className={styles.Box}>{item.description}</Box> : null}
18
{hierarchy ? (
19
<Hierarchy items={hierarchy} maxDepth={maxDepth} depth={depth + 1} hideVariants={hideVariants} />
20
) : null}
src/mdx/nav-hierarchy.module.css
new
+4
@@ -0,0 +1,4 @@
1
+.Box {
2
+ font-size: 14px;
3
+ margin-bottom: 4px;
4
+}
src/page.js
+22
-4
@@ -5,12 +5,30 @@ import Slugger from 'github-slugger'
5
import Header from './components/header'
6
import Sidebar from './components/sidebar'
7
import {SkipBox, SkipLink} from './components/skip-nav'
8
-import {SKIP_TO_CONTENT_ID, SKIP_TO_SEARCH_ID} from './constants'
8
+import {
9
+ SKIP_TO_CONTENT_ID,
10
+ SKIP_TO_SEARCH_ID,
11
+ HEADER_HEIGHT,
12
+ HEADER_BAR,
13
+ FULL_HEADER_HEIGHT,
14
+ SCROLL_MARGIN_TOP,
15
+ Z_INDEX,
16
+} from './constants'
17
18
import {PageProvider} from './hooks/use-page'
19
import Layout from './layout'
20
21
+import * as styles from './page.module.css'
22
+
23
const GlobalStyles = createGlobalStyle`
24
+ :root {
25
+ --header-height: ${HEADER_HEIGHT}px;
26
+ --header-bar: ${HEADER_BAR}px;
27
+ --full-header-height: ${FULL_HEADER_HEIGHT}px;
28
+ --scroll-margin-top: ${SCROLL_MARGIN_TOP}px;
29
+ --z-index-header: ${Z_INDEX.HEADER};
30
+ --z-index-search-overlay: ${Z_INDEX.SEARCH_OVERLAY};
31
+ }
32
body {
33
color: ${themeGet('colors.fg.default')};
34
background-color: ${themeGet('colors.canvas.default')};
@@ -33,10 +51,10 @@ const PageElement = ({element, props}) => {
51
<SkipLink href={`#${SKIP_TO_CONTENT_ID}`}>Skip to content</SkipLink>
52
</SkipBox>
53
<PageProvider value={page}>
36
- <Box sx={{display: 'flex', flexDirection: 'column', minHeight: '100vh'}}>
54
+ <Box className={styles.Box}>
55
<Header />
38
- <Box sx={{zIndex: 0, display: 'flex', flex: '1 1 auto', flexDirection: 'row'}}>
39
- <Box sx={{display: ['none', null, null, 'block']}}>
56
+ <Box className={styles.Box_1}>
57
+ <Box className={styles.sidebarContainer}>
58
<Sidebar />
59
</Box>
60
<Layout>{element}</Layout>
src/page.module.css
new
+22
@@ -0,0 +1,22 @@
1
+.Box {
2
+ display: flex;
3
+ flex-direction: column;
4
+ min-height: 100vh;
5
+}
6
+
7
+.Box_1 {
8
+ z-index: 0;
9
+ display: flex;
10
+ flex: 1 1 auto;
11
+ flex-direction: row;
12
+}
13
+
14
+.sidebarContainer {
15
+ display: none;
16
+}
17
+
18
+@media (min-width: 1012px) {
19
+ .sidebarContainer {
20
+ display: block;
21
+ }
22
+}