Refactor theme providers to a single file
Luke Karrys committed
Oct 20, 2023 at 18:58 UTC
86b10482456b82799d7cf4800f75d1d3e1c85c18
8 files changed
+70
-64
src/components/header.js
+9
-15
@@ -1,31 +1,25 @@
1
import React from 'react'
2
-import {Box, ThemeProvider} from '@primer/react'
2
+import {Box} from '@primer/react'
3
import styled from 'styled-components'
4
import MobileSearch from './mobile-search'
5
import NavDrawer from './nav-drawer'
6
import Search from './search'
7
import Link from './link'
8
import useSearch from '../hooks/use-search'
9
-import {HEADER_HEIGHT, HEADER_BAR, NPM_RED} from '../constants'
9
+import {HEADER_HEIGHT, HEADER_BAR} from '../constants'
10
import useSiteMetadata from '../hooks/use-site-metadata'
11
import headerNavItems from '../../content/header-nav.yml'
12
+import {DarkTheme} from '../theme'
13
14
const NpmHeaderBar = styled(Box)`
15
height: ${HEADER_BAR}px;
16
background-image: linear-gradient(139deg, #fb8817, #ff4b01, #c12127, #e02aff);
17
`
18
18
-const NpmLogo = ({size, ...props}) => (
19
- <Box {...props} role="banner">
20
- <svg
21
- height={size}
22
- width={size}
23
- viewBox="0 0 700 700"
24
- fill="currentColor"
25
- style={{color: NPM_RED}}
26
- aria-hidden="true"
27
- >
28
- <polygon fill={NPM_RED} points="0,700 700,700 700,0 0,0" />
19
+const NpmLogo = ({size, sx}) => (
20
+ <Box sx={{...sx, color: 'logoBg'}} role="banner">
21
+ <svg height={size} width={size} viewBox="0 0 700 700" fill="currentColor" aria-hidden="true">
22
+ <polygon fill="currentColor" points="0,700 700,700 700,0 0,0" />
23
<polygon fill="#ffffff" points="150,550 350,550 350,250 450,250 450,550 550,550 550,150 150,150 " />
24
</svg>
25
</Box>
@@ -36,7 +30,7 @@ function Header() {
30
const search = useSearch()
31
32
return (
39
- <ThemeProvider colorMode="night" nightScheme="dark_dimmed">
33
+ <DarkTheme>
34
<Box sx={{top: 0, position: 'sticky', zIndex: 1}}>
35
<NpmHeaderBar />
36
<Box
@@ -87,7 +81,7 @@ function Header() {
81
</Box>
82
</Box>
83
</Box>
90
- </ThemeProvider>
84
+ </DarkTheme>
85
)
86
}
87
src/components/mobile-search.js
+4
-3
@@ -1,5 +1,5 @@
1
import React from 'react'
2
-import {Button, Box, ThemeProvider} 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'
@@ -7,6 +7,7 @@ import TextInput from './text-input'
7
import SearchResults from './search-results'
8
import useSiteMetadata from '../hooks/use-site-metadata'
9
import {HEADER_BAR, HEADER_HEIGHT} from '../constants'
10
+import {LightTheme} from '../theme'
11
12
function MobileSearch({onDismiss, ...props}) {
13
const siteMetadata = useSiteMetadata()
@@ -81,7 +82,7 @@ function MobileSearch({onDismiss, ...props}) {
82
<XIcon />
83
</Button>
84
</Box>
84
- <ThemeProvider colorMode="light">
85
+ <LightTheme>
86
<Box
87
sx={{
88
display: 'flex',
@@ -98,7 +99,7 @@ function MobileSearch({onDismiss, ...props}) {
99
>
100
{isOpen ? <SearchResults {...{results, getItemProps, highlightedIndex}} /> : null}
101
</Box>
101
- </ThemeProvider>
102
+ </LightTheme>
103
</Box>
104
</Box>
105
</FocusOn>
src/components/nav-drawer.js
+6
-5
@@ -1,11 +1,12 @@
1
import React from 'react'
2
-import {Button, Box, ThemeProvider} from '@primer/react'
2
+import {Button, Box} from '@primer/react'
3
import {XIcon, ThreeBarsIcon} from '@primer/octicons-react'
4
import Link from './link'
5
import Drawer from './drawer'
6
import NavItems from './nav-items'
7
import useSiteMetadata from '../hooks/use-site-metadata'
8
import {useIsMobile} from '../hooks/use-breakpoint'
9
+import {DarkTheme, LightTheme} from '../theme'
10
11
const useDrawerIsOpen = () => {
12
const isMobile = useIsMobile()
@@ -31,7 +32,7 @@ function NavDrawer() {
32
<Button aria-label="Menu" aria-expanded={isOpen} onClick={setOpen} sx={{ml: 3}}>
33
<ThreeBarsIcon />
34
</Button>
34
- <ThemeProvider colorMode="light">
35
+ <LightTheme>
36
<Drawer isOpen={isOpen} onDismiss={setClose}>
37
<Box
38
sx={{
@@ -52,7 +53,7 @@ function NavDrawer() {
53
bg: 'canvas.default',
54
}}
55
>
55
- <ThemeProvider colorMode="night" nightScheme="dark_dimmed">
56
+ <DarkTheme>
57
<Box
58
sx={{
59
borderWidth: 0,
@@ -82,14 +83,14 @@ function NavDrawer() {
83
</Button>
84
</Box>
85
</Box>
85
- </ThemeProvider>
86
+ </DarkTheme>
87
<Box sx={{display: 'flex', flexDirection: 'column'}}>
88
<NavItems />
89
</Box>
90
</Box>
91
</Box>
92
</Drawer>
92
- </ThemeProvider>
93
+ </LightTheme>
94
</>
95
)
96
}
src/components/search.js
+4
-3
@@ -1,8 +1,9 @@
1
import React from 'react'
2
-import {Box, ThemeProvider} from '@primer/react'
2
+import {Box} from '@primer/react'
3
import TextInput from './text-input'
4
import SearchResults from './search-results'
5
import useSiteMetadata from '../hooks/use-site-metadata'
6
+import {LightTheme} from '../theme'
7
8
function Search(props) {
9
const siteMetadata = useSiteMetadata()
@@ -18,7 +19,7 @@ function Search(props) {
19
/>
20
<Box sx={{position: 'absolute', left: 0, right: 0, pt: 2}} {...getMenuProps()}>
21
{isOpen ? (
21
- <ThemeProvider colorMode="light">
22
+ <LightTheme>
23
<Box
24
sx={{
25
overflow: 'auto',
@@ -35,7 +36,7 @@ function Search(props) {
36
>
37
<SearchResults {...{results, getItemProps, highlightedIndex}} />
38
</Box>
38
- </ThemeProvider>
39
+ </LightTheme>
40
) : null}
41
</Box>
42
</Box>
src/constants.js
-2
@@ -5,5 +5,3 @@ export const HEADER_BAR = 10
5
export const FULL_HEADER_HEIGHT = HEADER_HEIGHT + HEADER_BAR
6
7
export const SKIP_NAV = {id: 'skip-nav', as: 'main'}
8
-
9
-export const NPM_RED = '#cb0000'
src/layout.js
+4
-3
@@ -1,5 +1,5 @@
1
import React from 'react'
2
-import {Box, Heading, Text, ThemeProvider} from '@primer/react'
2
+import {Box, Heading, Text} from '@primer/react'
3
import {H1} from './mdx'
4
import PageFooter from './components/page-footer'
5
import * as TableOfContents from './components/table-of-contents'
@@ -9,13 +9,14 @@ import Container from './components/container'
9
import {SKIP_NAV} from './constants'
10
import useSiteMetadata from './hooks/use-site-metadata'
11
import usePage from './hooks/use-page'
12
+import {DarkTheme} from './theme'
13
14
const HeroLayout = ({children}) => {
15
const {title, description} = useSiteMetadata()
16
17
return (
18
<Box sx={{width: '100%'}} {...SKIP_NAV}>
18
- <ThemeProvider colorMode="night" nightScheme="dark_dimmed">
19
+ <DarkTheme>
20
<Box sx={{bg: 'canvas.inset', py: 6}}>
21
<Container>
22
<Heading as="h1" sx={{color: 'fg.default', fontSize: 7, m: 0}}>
@@ -26,7 +27,7 @@ const HeroLayout = ({children}) => {
27
</Text>
28
</Container>
29
</Box>
29
- </ThemeProvider>
30
+ </DarkTheme>
31
<Container>{children}</Container>
32
</Box>
33
)
src/root.js
+2
-33
@@ -1,38 +1,7 @@
1
import React from 'react'
2
import {MDXProvider} from '@mdx-js/react'
3
-import {ThemeProvider, theme} from '@primer/react'
4
-import deepmerge from 'deepmerge'
3
+import {ThemeProvider} from './theme'
4
import * as Components from './mdx'
6
-import {NPM_RED} from './constants'
7
-
8
-const npmTheme = deepmerge(theme, {
9
- colorSchemes: {
10
- light: {
11
- colors: {
12
- accent: {
13
- fg: NPM_RED,
14
- },
15
- },
16
- },
17
- dark_dimmed: {
18
- colors: {
19
- canvas: {
20
- default: '#333333',
21
- },
22
- fg: {
23
- default: '#E1E4E8',
24
- },
25
- btn: {
26
- text: '#E1E4E8',
27
- bg: 'transparent',
28
- border: '#444D56',
29
- hoverBorder: '#444D56',
30
- hoverBg: NPM_RED,
31
- },
32
- },
33
- },
34
- },
35
-})
5
6
const components = {
7
a: Components.Link,
@@ -62,7 +31,7 @@ const components = {
31
32
const RootElement = ({element}) => (
33
<MDXProvider components={components}>
65
- <ThemeProvider theme={npmTheme}>{element}</ThemeProvider>
34
+ <ThemeProvider>{element}</ThemeProvider>
35
</MDXProvider>
36
)
37
src/theme.js
new
+41
@@ -0,0 +1,41 @@
1
+import React from 'react'
2
+import {ThemeProvider as PrimerThemeProvider, theme as primerTheme} from '@primer/react'
3
+import deepmerge from 'deepmerge'
4
+
5
+export const NPM_RED = '#cb0000'
6
+
7
+export const theme = deepmerge(primerTheme, {
8
+ colors: {
9
+ logoBg: NPM_RED,
10
+ },
11
+ colorSchemes: {
12
+ light: {
13
+ colors: {
14
+ accent: {
15
+ fg: NPM_RED,
16
+ },
17
+ },
18
+ },
19
+ dark_dimmed: {
20
+ colors: {
21
+ canvas: {
22
+ default: '#333333',
23
+ },
24
+ fg: {
25
+ default: '#E1E4E8',
26
+ },
27
+ btn: {
28
+ text: '#E1E4E8',
29
+ bg: 'transparent',
30
+ border: '#444D56',
31
+ hoverBorder: '#444D56',
32
+ hoverBg: NPM_RED,
33
+ },
34
+ },
35
+ },
36
+ },
37
+})
38
+
39
+export const ThemeProvider = props => <PrimerThemeProvider theme={theme} {...props} />
40
+export const LightTheme = props => <ThemeProvider colorMode="light" {...props} />
41
+export const DarkTheme = props => <ThemeProvider colorMode="dark" nightScheme="dark_dimmed" {...props} />