Add top nav links to nav drawer

Luke Karrys committed Oct 16, 2023 at 16:20 UTC b336b1b7de54f0675efbdc0ba3e12a208ba46345
6 files changed +90 -88
content/nav.yml
+2 -2
@@ -276,8 +276,8 @@
276 url: /policies/security
277 - title: Replication and web crawler policy
278 url: /policies/crawlers
279 -- title: Threats and Mitigations
280 - shortName: threats and mitigations
279 +- title: Threats and mitigations
280 + shortName: Threats and mitigations
281 url: /threats-and-mitigations
282 - title: npm CLI
283 shortName: CLI
src/components/header.js
+56 -54
@@ -1,5 +1,5 @@
1 import React from 'react'
2 -import {Box, Link} from '@primer/react'
2 +import {Box, Link, ThemeProvider} from '@primer/react'
3 import {Link as GatsbyLink} from 'gatsby'
4 import styled from 'styled-components'
5 import MobileSearch from './mobile-search'
@@ -15,18 +15,20 @@ const NpmHeaderBar = styled(Box)`
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>
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" />
29 + <polygon fill="#ffffff" points="150,550 350,550 350,250 450,250 450,550 550,550 550,150 150,150 " />
30 + </svg>
31 + </Box>
32 )
33
34 function Header() {
@@ -34,57 +36,57 @@ function Header() {
36 const search = useSearch()
37
38 return (
37 - <Box sx={{top: 0, position: 'sticky', zIndex: 1}} role="banner">
38 - <NpmHeaderBar />
39 - <Box
40 - as="header"
41 - sx={{
42 - display: 'flex',
43 - height: HEADER_HEIGHT - HEADER_BAR,
44 - px: [3, null, null, 4],
45 - alignItems: 'center',
46 - justifyContent: 'space-between',
47 - bg: 'canvas.default',
48 - border: '1px solid',
49 - borderColor: 'border.muted',
50 - }}
51 - >
52 - <Box sx={{display: 'flex', alignItems: 'center'}}>
53 - <Link
54 - as={GatsbyLink}
55 - to="/"
56 - sx={{
57 - mr: 4,
58 - fontWeight: 'bold',
59 - color: 'fg.default',
60 - display: 'flex',
61 - alignItems: 'center',
62 - }}
63 - >
64 - <NpmLogo size="32" sx={{mr: '16px'}} />
65 - {siteMetadata.title}
66 - </Link>
67 - <Box sx={{display: ['none', null, null, 'block'], ml: 4}}>
68 - <Search {...search} />
39 + <ThemeProvider colorMode="night" nightScheme="dark_dimmed">
40 + <Box sx={{top: 0, position: 'sticky', zIndex: 1}}>
41 + <NpmHeaderBar />
42 + <Box
43 + as="header"
44 + sx={{
45 + display: 'flex',
46 + height: HEADER_HEIGHT - HEADER_BAR,
47 + px: [3, null, null, 4],
48 + alignItems: 'center',
49 + justifyContent: 'space-between',
50 + bg: 'canvas.default',
51 + border: '1px solid',
52 + borderColor: 'border.muted',
53 + }}
54 + >
55 + <Box sx={{display: 'flex', alignItems: 'center'}}>
56 + <Link
57 + as={GatsbyLink}
58 + to="/"
59 + sx={{
60 + mr: 4,
61 + fontWeight: 'bold',
62 + color: 'fg.default',
63 + display: 'flex',
64 + alignItems: 'center',
65 + }}
66 + >
67 + <NpmLogo size="32" sx={{mr: '16px'}} />
68 + {siteMetadata.title}
69 + </Link>
70 + <Box sx={{display: ['none', null, null, 'block'], ml: 4}}>
71 + <Search {...search} />
72 + </Box>
73 </Box>
70 - </Box>
71 - <Box sx={{display: 'flex'}}>
72 - <Box sx={{display: ['none', null, null, 'block']}}>
73 - <Box sx={{display: 'flex', alignItems: 'center', color: 'gray.2'}}>
74 + <Box sx={{display: 'flex'}}>
75 + <Box sx={{display: ['none', null, null, 'flex'], alignItems: 'center'}}>
76 {headerNavItems.map((item, index) => (
77 <Link key={index} href={item.url} sx={{display: 'block', ml: 4}}>
78 {item.title}
79 </Link>
80 ))}
81 </Box>
80 - </Box>
81 - <Box sx={{display: ['flex', null, null, 'none']}}>
82 - <MobileSearch {...search} />
83 - <NavDrawer />
82 + <Box sx={{display: ['flex', null, null, 'none']}}>
83 + <MobileSearch {...search} />
84 + <NavDrawer />
85 + </Box>
86 </Box>
87 </Box>
88 </Box>
87 - </Box>
89 + </ThemeProvider>
90 )
91 }
92
src/components/mobile-search.js
+13 -2
@@ -6,6 +6,7 @@ import {FocusOn} from 'react-focus-on'
6 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
11 function MobileSearch({onDismiss, ...props}) {
12 const siteMetadata = useSiteMetadata()
@@ -21,7 +22,7 @@ function MobileSearch({onDismiss, ...props}) {
22 <Box
23 sx={{
24 position: 'fixed',
24 - top: '10px', // TODO: use constant
25 + top: `${HEADER_BAR}px`,
26 left: 0,
27 right: 0,
28 bottom: 0,
@@ -45,7 +46,17 @@ function MobileSearch({onDismiss, ...props}) {
46 onClick={handleDismiss}
47 />
48 <Box sx={{display: 'flex', flexDirection: 'column', height: isOpen ? '100%' : 'auto'}}>
48 - <Box sx={{display: 'flex', bg: 'canvas.default', color: 'fg.default', p: 3, flex: '0 0 auto'}}>
49 + <Box
50 + sx={{
51 + display: 'flex',
52 + bg: 'canvas.default',
53 + color: 'fg.default',
54 + height: `${HEADER_HEIGHT - HEADER_BAR}px`,
55 + flex: '0 0 auto',
56 + px: 3,
57 + alignItems: 'center',
58 + }}
59 + >
60 <motion.div
61 initial={{scaleX: 0.1}}
62 animate={{scaleX: 1}}
src/components/nav-drawer.js
-23
@@ -6,7 +6,6 @@ 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 headerNavItems from '../../content/header-nav.yml'
9
10 const useDrawerIsOpen = () => {
11 const isMobile = useIsMobile()
@@ -77,28 +76,6 @@ function NavDrawer() {
76 <NavItems />
77 </Box>
78 </Box>
80 - <Box
81 - sx={{flexDirection: 'column', flex: '1 0 auto', color: 'fg.default', bg: 'canvas.default', display: 'flex'}}
82 - >
83 - {headerNavItems.map((item, index) => (
84 - <Box
85 - key={item.title}
86 - sx={{
87 - borderWidth: 0,
88 - borderRadius: 0,
89 - borderTopWidth: index !== 0 ? 1 : 0,
90 - borderColor: 'border.muted',
91 - px: 4,
92 - py: 3,
93 - borderStyle: 'solid',
94 - }}
95 - >
96 - <Link key={index} href={item.url} sx={{color: 'inherit', display: 'block'}}>
97 - {item.title}
98 - </Link>
99 - </Box>
100 - ))}
101 - </Box>
79 </Box>
80 </Drawer>
81 </>
src/components/nav-items.js
+19 -6
@@ -5,6 +5,7 @@ import {LinkExternalIcon} from '@primer/octicons-react'
5 import * as getNav from '../util/get-nav'
6 import {useLocation, usePageContext} from '../layout'
7 import VisuallyHidden from './visually-hidden'
8 +import headerNavItems from '../../content/header-nav.yml'
9
10 const NavItem = ({item, path}) => {
11 const href = getNav.getLocation(item.url)
@@ -31,6 +32,15 @@ const NavItems = ({items, path}) => (
32 </>
33 )
34
35 +const ExternalNavItem = ({title, href, ...props}) => (
36 + <NavList.Item {...props}>
37 + {title}
38 + <NavList.TrailingVisual>
39 + <LinkExternalIcon />
40 + </NavList.TrailingVisual>
41 + </NavList.Item>
42 +)
43 +
44 const Navigation = () => {
45 const location = useLocation()
46 const {repositoryUrl} = usePageContext()
@@ -45,12 +55,15 @@ const Navigation = () => {
55 <NavList aria-label="Site">
56 <NavItems items={items} path={path} />
57 <NavList.Divider />
48 - <NavList.Item href={repositoryUrl}>
49 - GitHub
50 - <NavList.TrailingVisual>
51 - <LinkExternalIcon />
52 - </NavList.TrailingVisual>
53 - </NavList.Item>
58 + {headerNavItems.map(item => (
59 + <ExternalNavItem
60 + key={item.title}
61 + title={item.title}
62 + href={item.url}
63 + sx={{display: ['flex', null, null, 'none']}}
64 + />
65 + ))}
66 + <ExternalNavItem title="GitHub" href={repositoryUrl} />
67 </NavList>
68 </>
69 )
src/components/sidebar.js
-1
@@ -43,7 +43,6 @@ const Sidebar = () => (
43 sx={{
44 borderWidth: 0,
45 borderRightWidth: 1,
46 - borderRadius: 0,
46 height: '100%',
47 borderStyle: 'solid',
48 borderColor: 'border.subtle',