Make theme wrapper components use as property for less nesting

Luke Karrys committed Oct 22, 2023 at 11:13 UTC a355a6af3ce2acc27ce0c4695883e2c42ba99ffd
5 files changed +135 -140
src/components/header.js
+45 -47
@@ -29,54 +29,52 @@ function Header() {
29 const search = useSearch()
30
31 return (
32 - <DarkTheme>
33 - <Box sx={{top: 0, position: 'sticky', zIndex: 1}}>
34 - <NpmHeaderBar />
35 - <Box
36 - as="header"
37 - sx={{
38 - display: 'flex',
39 - height: HEADER_HEIGHT,
40 - px: [3, null, null, 4],
41 - alignItems: 'center',
42 - justifyContent: 'space-between',
43 - bg: 'canvas.default',
44 - border: '1px solid',
45 - borderLeftWidth: 0,
46 - borderRightWidth: 0,
47 - borderColor: 'border.muted',
48 - }}
49 - >
50 - <Box sx={{display: 'flex', alignItems: 'center'}}>
51 - <Link
52 - to="/"
53 - sx={{
54 - mr: 4,
55 - fontWeight: 'bold',
56 - color: 'fg.default',
57 - display: 'flex',
58 - alignItems: 'center',
59 - }}
60 - >
61 - <NpmLogo size="32" sx={{display: 'flex', mr: 3}} />
62 - {siteMetadata.title}
63 - </Link>
64 - <Box sx={{display: ['none', null, null, 'block'], ml: 4}}>
65 - <Search.Desktop {...search} />
66 - </Box>
32 + <DarkTheme sx={{top: 0, position: 'sticky', zIndex: 1}}>
33 + <NpmHeaderBar />
34 + <Box
35 + as="header"
36 + sx={{
37 + display: 'flex',
38 + height: HEADER_HEIGHT,
39 + px: [3, null, null, 4],
40 + alignItems: 'center',
41 + justifyContent: 'space-between',
42 + bg: 'canvas.default',
43 + border: '1px solid',
44 + borderLeftWidth: 0,
45 + borderRightWidth: 0,
46 + borderColor: 'border.muted',
47 + }}
48 + >
49 + <Box sx={{display: 'flex', alignItems: 'center'}}>
50 + <Link
51 + to="/"
52 + sx={{
53 + mr: 4,
54 + fontWeight: 'bold',
55 + color: 'fg.default',
56 + display: 'flex',
57 + alignItems: 'center',
58 + }}
59 + >
60 + <NpmLogo size="32" sx={{display: 'flex', mr: 3}} />
61 + {siteMetadata.title}
62 + </Link>
63 + <Box sx={{display: ['none', null, null, 'block'], ml: 4}}>
64 + <Search.Desktop {...search} />
65 </Box>
68 - <Box sx={{display: 'flex'}}>
69 - <Box sx={{display: ['none', null, null, 'flex'], alignItems: 'center'}}>
70 - {headerNavItems.map((item, index) => (
71 - <Link key={index} href={item.url} sx={{display: 'block', ml: 4, color: 'fg.default'}}>
72 - {item.title}
73 - </Link>
74 - ))}
75 - </Box>
76 - <Box sx={{display: ['flex', null, null, 'none']}}>
77 - <Search.Mobile {...search} />
78 - <NavDrawer />
79 - </Box>
66 + </Box>
67 + <Box sx={{display: 'flex'}}>
68 + <Box sx={{display: ['none', null, null, 'flex'], alignItems: 'center'}}>
69 + {headerNavItems.map((item, index) => (
70 + <Link key={index} href={item.url} sx={{display: 'block', ml: 4, color: 'fg.default'}}>
71 + {item.title}
72 + </Link>
73 + ))}
74 + </Box>
75 + <Box sx={{display: ['flex', null, null, 'none']}}>
76 + <Search.Mobile {...search} />
77 + <NavDrawer />
78 </Box>
79 </Box>
80 </Box>
src/components/nav-drawer.js
+40 -44
@@ -32,64 +32,60 @@ function NavDrawer() {
32 <Button aria-label="Menu" aria-expanded={isOpen} onClick={setOpen} sx={{ml: 3}}>
33 <ThreeBarsIcon />
34 </Button>
35 - <LightTheme>
36 - <Drawer isOpen={isOpen} onDismiss={setClose}>
35 + <LightTheme as={Drawer} isOpen={isOpen} onDismiss={setClose}>
36 + <Box
37 + sx={{
38 + display: 'flex',
39 + flexDirection: 'column',
40 + height: '100%',
41 + bg: 'canvas.backdrop',
42 + overflow: 'auto',
43 + }}
44 + style={{WebkitOverflowScrolling: 'touch'}}
45 + >
46 <Box
47 sx={{
48 display: 'flex',
49 flexDirection: 'column',
41 - height: '100%',
42 - bg: 'canvas.backdrop',
43 - overflow: 'auto',
50 + flex: '1 0 auto',
51 + color: 'fg.default',
52 + bg: 'canvas.default',
53 }}
45 - style={{WebkitOverflowScrolling: 'touch'}}
54 >
47 - <Box
55 + <DarkTheme
56 sx={{
49 - display: 'flex',
50 - flexDirection: 'column',
51 - flex: '1 0 auto',
57 + borderWidth: 0,
58 + borderRadius: 0,
59 + borderBottomWidth: 1,
60 + borderColor: 'border.muted',
61 + borderStyle: 'solid',
62 color: 'fg.default',
63 bg: 'canvas.default',
64 }}
65 >
56 - <DarkTheme>
57 - <Box
58 - sx={{
59 - borderWidth: 0,
60 - borderRadius: 0,
61 - borderBottomWidth: 1,
62 - borderColor: 'border.muted',
63 - borderStyle: 'solid',
64 - color: 'fg.default',
65 - bg: 'canvas.default',
66 - }}
67 - >
68 - <Box
69 - sx={{
70 - py: 3,
71 - pl: 4,
72 - pr: 3,
73 - alignItems: 'center',
74 - justifyContent: 'space-between',
75 - display: 'flex',
76 - }}
77 - >
78 - <Link to="/" sx={{fontSize: 2, color: 'fg.default'}}>
79 - {siteMetadata.title}
80 - </Link>
81 - <Button aria-label="Close" onClick={setClose}>
82 - <XIcon />
83 - </Button>
84 - </Box>
85 - </Box>
86 - </DarkTheme>
87 - <Box sx={{display: 'flex', flexDirection: 'column'}}>
88 - <NavItems />
66 + <Box
67 + sx={{
68 + py: 3,
69 + pl: 4,
70 + pr: 3,
71 + alignItems: 'center',
72 + justifyContent: 'space-between',
73 + display: 'flex',
74 + }}
75 + >
76 + <Link to="/" sx={{fontSize: 2, color: 'fg.default'}}>
77 + {siteMetadata.title}
78 + </Link>
79 + <Button aria-label="Close" onClick={setClose}>
80 + <XIcon />
81 + </Button>
82 </Box>
83 + </DarkTheme>
84 + <Box sx={{display: 'flex', flexDirection: 'column'}}>
85 + <NavItems />
86 </Box>
87 </Box>
92 - </Drawer>
88 + </Box>
89 </LightTheme>
90 </>
91 )
src/components/search.js
+29 -33
@@ -23,22 +23,20 @@ export const Desktop = props => {
23 />
24 <Box sx={{position: 'absolute', left: 0, right: 0, pt: 1}} {...getMenuProps()}>
25 {isOpen ? (
26 - <LightTheme>
27 - <Box
28 - sx={{
29 - overflow: 'auto',
30 - minWidth: 300,
31 - maxHeight: '70vh',
32 - boxShadow: 'shadow.large',
33 - borderColor: 'border.muted',
34 - bg: 'canvas.overlay',
35 - borderRadius: 2,
36 - borderWidth: 1,
37 - borderStyle: 'solid',
38 - }}
39 - >
40 - <SearchResults {...{results, getItemProps, highlightedIndex}} />
41 - </Box>
26 + <LightTheme
27 + sx={{
28 + overflow: 'auto',
29 + minWidth: 300,
30 + maxHeight: '70vh',
31 + boxShadow: 'shadow.large',
32 + borderColor: 'border.muted',
33 + bg: 'canvas.overlay',
34 + borderRadius: 2,
35 + borderWidth: 1,
36 + borderStyle: 'solid',
37 + }}
38 + >
39 + <SearchResults {...{results, getItemProps, highlightedIndex}} />
40 </LightTheme>
41 ) : null}
42 </Box>
@@ -175,23 +173,21 @@ export const Mobile = props => {
173 </Button>
174 </Box>
175 </Box>
178 - <LightTheme>
179 - <Box
180 - sx={{
181 - display: 'flex',
182 - bg: 'canvas.default',
183 - py: resultsOpen ? 1 : 0,
184 - flexDirection: 'column',
185 - flex: '1 1 auto',
186 - overflow: 'auto',
187 - }}
188 - style={{
189 - WebkitOverflowScrolling: 'touch',
190 - }}
191 - {...getMenuProps()}
192 - >
193 - {resultsOpen ? <SearchResults {...{results, getItemProps, highlightedIndex}} /> : null}
194 - </Box>
176 + <LightTheme
177 + sx={{
178 + display: 'flex',
179 + bg: 'canvas.default',
180 + py: resultsOpen ? 1 : 0,
181 + flexDirection: 'column',
182 + flex: '1 1 auto',
183 + overflow: 'auto',
184 + }}
185 + style={{
186 + WebkitOverflowScrolling: 'touch',
187 + }}
188 + {...getMenuProps()}
189 + >
190 + {resultsOpen ? <SearchResults {...{results, getItemProps, highlightedIndex}} /> : null}
191 </LightTheme>
192 </Box>
193 </Box>
src/layout.js
+9 -11
@@ -16,17 +16,15 @@ const HeroLayout = ({children}) => {
16
17 return (
18 <Box as="main" sx={{width: '100%'}}>
19 - <DarkTheme>
20 - <Box sx={{bg: 'canvas.inset', py: 6}}>
21 - <Container>
22 - <Heading as="h1" sx={{color: 'fg.default', fontSize: 7, m: 0}}>
23 - {title}
24 - </Heading>
25 - <Text as="p" sx={{m: 0, color: 'fg.onEmphasis', fontSize: 4}}>
26 - {description}
27 - </Text>
28 - </Container>
29 - </Box>
19 + <DarkTheme sx={{bg: 'canvas.inset', py: 6}}>
20 + <Container>
21 + <Heading as="h1" sx={{color: 'fg.default', fontSize: 7, m: 0}}>
22 + {title}
23 + </Heading>
24 + <Text as="p" sx={{m: 0, color: 'fg.onEmphasis', fontSize: 4}}>
25 + {description}
26 + </Text>
27 + </Container>
28 </DarkTheme>
29 <SkipNav />
30 <Container>{children}</Container>
src/theme.js
+12 -5
@@ -1,10 +1,10 @@
1 import React from 'react'
2 -import {ThemeProvider as PrimerThemeProvider, theme as primerTheme} from '@primer/react'
2 +import {ThemeProvider as Provider, theme, Box} from '@primer/react'
3 import deepmerge from 'deepmerge'
4
5 export const NPM_RED = '#cb0000'
6
7 -export const theme = deepmerge(primerTheme, {
7 +export const npmTheme = deepmerge(theme, {
8 colors: {
9 logoBg: NPM_RED,
10 },
@@ -37,6 +37,13 @@ export const theme = deepmerge(primerTheme, {
37 },
38 })
39
40 -export const ThemeProvider = props => <PrimerThemeProvider theme={theme} {...props} />
41 -export const LightTheme = props => <ThemeProvider colorMode="light" {...props} />
42 -export const DarkTheme = props => <ThemeProvider colorMode="dark" nightScheme="dark_dimmed" {...props} />
40 +export const ThemeProvider = props => <Provider theme={npmTheme} {...props} />
41 +
42 +export const Theme = ({theme: colorMode, as = Box, ...props}) => (
43 + <Provider colorMode={colorMode} nightScheme="dark_dimmed">
44 + {React.createElement(as, props)}
45 + </Provider>
46 +)
47 +
48 +export const LightTheme = props => <Theme theme="light" {...props} />
49 +export const DarkTheme = props => <Theme theme="dark" {...props} />