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} />