Skip to content

Commit 17e8be6

Browse files
authored
Mobile header (#195)
* move header to own component * upgrade react (for hooks), init mobile menu * mobile nav * close on click
1 parent a85725c commit 17e8be6

File tree

8 files changed

+233
-84
lines changed

8 files changed

+233
-84
lines changed

package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,8 @@
2727
"gatsby-transformer-remark": "^1.7.7",
2828
"just-safe-get": "^2.0.0",
2929
"prismjs": "^1.15.0",
30-
"react": "^16.0.0",
31-
"react-dom": "^16.0.0",
30+
"react": "^16.8.0",
31+
"react-dom": "^16.8.0",
3232
"react-helmet": "^5.2.0",
3333
"styletron-client": "^3.0.0-rc.1",
3434
"styletron-react": "^3.0.0-rc.2",

src/components/burger-menu-button.js

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
import React from 'react';
2+
import { bool, func } from 'prop-types';
3+
4+
import { StyledBurger, StyledBurgerBar } from './styled-elements';
5+
6+
const Burger = ({ open, setOpen }) => {
7+
const handleClick = () => setOpen(!open)
8+
return (
9+
<StyledBurger onClick={handleClick}>
10+
<StyledBurgerBar styleProps={{open}} />
11+
<StyledBurgerBar styleProps={{open}} />
12+
<StyledBurgerBar styleProps={{open}} />
13+
</StyledBurger>
14+
)
15+
}
16+
17+
Burger.propTypes = {
18+
open: bool.isRequired,
19+
setOpen: func.isRequired,
20+
};
21+
22+
export default Burger;

src/components/main-nav.js renamed to src/components/nav-items.js

Lines changed: 10 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import React from 'react';
22
import {styled} from 'styletron-react';
33
import Helmet from 'react-helmet';
44
import Link from 'gatsby-link';
5-
import {MainNavContainer, MainNavItem, SearchField} from './styled-elements';
5+
import { MainNavItem, SearchField } from './styled-elements';
66
import {getPath} from '../utils';
77

88
const InternalLink = props => {
@@ -20,7 +20,7 @@ class DocsSearch extends React.Component {
2020
<SearchField
2121
styleProps={{
2222
overrides: {
23-
'@media (max-width: 355px)': {
23+
'@media (max-width: 587px)': {
2424
display: 'none',
2525
},
2626
verticalAlign: 'baseline !important',
@@ -33,7 +33,7 @@ class DocsSearch extends React.Component {
3333
}
3434
}
3535

36-
const Nav = props => {
36+
const NavItems = props => {
3737
const {data, location, pathPrefix} = props;
3838

3939
function matchPath(regexp) {
@@ -45,8 +45,10 @@ const Nav = props => {
4545
return matchPath(reNews);
4646
}
4747

48+
const handleLinkClick = () => props.setOpenMobileMenu()
49+
4850
return (
49-
<MainNavContainer data-test="main-nav">
51+
<React.Fragment>
5052
{data.map((item, index) => {
5153
const re = new RegExp(`^${pathPrefix}${item.pathPrefix}(/|$)`);
5254
const isActive = matchPath(re);
@@ -55,6 +57,7 @@ const Nav = props => {
5557
<InternalLink
5658
key={index}
5759
to={item.path || getPath(item.pathPrefix, item.children[0])}
60+
onClick={handleLinkClick}
5861
>
5962
{isActive ? (
6063
<Helmet
@@ -66,23 +69,18 @@ const Nav = props => {
6669
</InternalLink>
6770
);
6871
})}
69-
<InternalLink to="/support">
72+
<InternalLink to="/support" onClick={handleLinkClick}>
7073
<MainNavItem
7174
styleProps={{
7275
isActive: isActive('/support'),
73-
overrides: {
74-
'@media (max-width: 474px)': {
75-
display: 'none',
76-
},
77-
},
7876
}}
7977
>
8078
Support
8179
</MainNavItem>
8280
</InternalLink>
8381
<DocsSearch />
84-
</MainNavContainer>
82+
</React.Fragment>
8583
);
8684
};
8785

88-
export default Nav;
86+
export default NavItems;

src/components/page-header.js

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
import React, { useState } from 'react';
2+
import Link from 'gatsby-link';
3+
import {
4+
H1,
5+
Header,
6+
HeaderTitle,
7+
MainNavContainer,
8+
MobileNavContainer,
9+
} from './styled-elements';
10+
import {
11+
PageWidth,
12+
FlexContainer,
13+
FlexItem,
14+
} from '../layouts/styled-elements';
15+
import Burger from './burger-menu-button';
16+
import NavItems from './nav-items';
17+
import docsContents from '../nav-docs.yml';
18+
import apiContents from '../nav-api.yml';
19+
20+
const PageHeader = ({
21+
location,
22+
pathPrefix,
23+
}) => {
24+
const [mobileMenuOpen, setMobileMenuOpen] = useState(false)
25+
const handlSetOpen = () => { setMobileMenuOpen(!mobileMenuOpen) };
26+
27+
return (
28+
<Header>
29+
<Burger open={mobileMenuOpen} setOpen={handlSetOpen} />
30+
<PageWidth>
31+
<FlexContainer>
32+
<FlexItem>
33+
<H1>
34+
<Link to="/" style={{ backgroundColor: 'transparent' }}>
35+
<HeaderTitle>Fusion.js</HeaderTitle>
36+
</Link>
37+
</H1>
38+
</FlexItem>
39+
<FlexItem>
40+
<MainNavContainer data-test="main-nav">
41+
<NavItems
42+
data={[docsContents, apiContents]}
43+
location={location}
44+
pathPrefix={pathPrefix}
45+
setOpenMobileMenu={handlSetOpen}
46+
/>
47+
</MainNavContainer>
48+
</FlexItem>
49+
</FlexContainer>
50+
{mobileMenuOpen && (
51+
<MobileNavContainer>
52+
<NavItems
53+
data={[docsContents, apiContents]}
54+
location={location}
55+
pathPrefix={pathPrefix}
56+
setOpenMobileMenu={handlSetOpen}
57+
/>
58+
</MobileNavContainer>
59+
)}
60+
</PageWidth>
61+
</Header>
62+
)
63+
}
64+
65+
export default PageHeader;

src/components/styled-elements.js

Lines changed: 101 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,18 @@ const {
99
fontFamily,
1010
} = require('./style-settings');
1111

12-
exports.MainNavContainer = styled('div', {});
12+
exports.MainNavContainer = styled('div', () => ({
13+
'@media (max-width: 587px)': {
14+
display: 'none',
15+
},
16+
}));
17+
18+
exports.MobileNavContainer = styled('div', () => ({
19+
paddingBottom: '15px',
20+
'@media (min-width: 588px)': {
21+
display: 'none',
22+
},
23+
}));
1324

1425
exports.SearchField = styled('input', ({styleProps = {}}) => ({
1526
boxSizing: 'border-box',
@@ -55,10 +66,10 @@ exports.MainNavItem = styled('span', ({styleProps = {}}) => ({
5566
textDecoration: 'none',
5667
lineHeight: '1',
5768
padding: '17px 15px 19px 15px',
58-
borderTopWidth: '4px',
59-
borderTopStyle: 'solid',
69+
borderBottomWidth: '4px',
70+
borderBottomStyle: 'solid',
6071
color: styleProps.isActive ? whiteColor : white120Color,
61-
borderTopColor: styleProps.isActive ? primaryColor : 'transparent',
72+
borderBottomColor: styleProps.isActive ? primaryColor : 'transparent',
6273
':hover': {
6374
color: whiteColor,
6475
},
@@ -69,6 +80,9 @@ exports.MainNavItem = styled('span', ({styleProps = {}}) => ({
6980
padding: '17px 4px 19px 4px',
7081
letterSpacing: '1px',
7182
},
83+
'@media (max-width: 587px)': {
84+
width: '97vw'
85+
},
7286
...styleProps.overrides,
7387
}));
7488

@@ -94,6 +108,52 @@ exports.SideNavUl = styled('ul', ({styleProps = {}}) => ({
94108
...styleProps.overrides,
95109
}));
96110

111+
exports.StyledBurger = styled('button', ({styleProps = {}}) => ({
112+
position: 'absolute',
113+
top: '10px',
114+
right: '15px',
115+
display: 'flex',
116+
flexDirection: 'column',
117+
justifyContent: 'space-around',
118+
width: '32px',
119+
height: '32px',
120+
background: 'transparent',
121+
border: 'none',
122+
cursor: 'pointer',
123+
padding: '0',
124+
zIndex: '99',
125+
126+
':focus': {
127+
outline: 'none'
128+
},
129+
130+
'@media (min-width: 588px)': {
131+
display: 'none',
132+
},
133+
}));
134+
135+
exports.StyledBurgerBar = styled('div', ({ styleProps = {} }) => ({
136+
width: '32px',
137+
height: '2px',
138+
backgroundColor: whiteColor,
139+
transition: 'all 0.3s linear',
140+
position: 'relative',
141+
transformOrigin: '1px',
142+
143+
':first-child': {
144+
transform: styleProps.open ? 'rotate(45deg)' : 'rotate(0)',
145+
},
146+
147+
':nth-child(2)': {
148+
opacity: styleProps.open ? '0' : '1',
149+
transform: styleProps.open ? 'translateX(20px)' : 'translateX(0)',
150+
},
151+
152+
':nth-child(3)': {
153+
transform: styleProps.open ? 'rotate(-45deg)' : 'rotate(0)',
154+
},
155+
}));
156+
97157
exports.SideNavLi = styled('li', ({styleProps = {}}) => ({
98158
margin: '0',
99159
...styleProps.overrides,
@@ -123,3 +183,40 @@ exports.SideNavItem = styled('span', ({styleProps = {}}) => ({
123183
},
124184
...styleProps.overrides,
125185
}));
186+
187+
exports.Header = styled('div', {
188+
position: 'fixed',
189+
top: 0,
190+
left: 0,
191+
right: 0,
192+
minHeight: '52px',
193+
background: '#041725',
194+
color: whiteColor,
195+
zIndex: '999',
196+
});
197+
198+
exports.HeaderTitle = styled('span', {
199+
backgroundColor: 'transparent',
200+
display: 'inline-block',
201+
fontWeight: '100',
202+
fontSize: '20px',
203+
textTransform: 'uppercase',
204+
letterSpacing: '4px',
205+
textDecoration: 'none',
206+
color: whiteColor,
207+
paddingTop: '16px',
208+
paddingBottom: '16px',
209+
paddingLeft: '15px',
210+
paddingRight: '15px',
211+
lineHeight: '1',
212+
':hover': {
213+
textDecoration: 'none',
214+
},
215+
});
216+
217+
exports.H1 = styled('h1', {
218+
marginTop: '0',
219+
marginBottom: '0',
220+
marginLeft: '0',
221+
marginRight: '0',
222+
});

src/layouts/index.js

Lines changed: 5 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,17 @@
11
import React from 'react';
22
import PropTypes from 'prop-types';
33
import Helmet from 'react-helmet';
4-
import Link from 'gatsby-link';
54
import {
65
Page,
76
PageWidth,
8-
H1,
9-
Header,
10-
HeaderTitle,
117
Body,
128
FlexContainer,
139
FlexItem,
1410
SideNavContainer,
1511
Content,
1612
} from './styled-elements';
17-
import MainNav from '../components/main-nav';
1813
import SideNav from '../components/side-nav';
14+
import PageHeader from '../components/page-header';
1915
import Footer from '../components/footer';
2016
import docsContents from '../nav-docs.yml';
2117
import apiContents from '../nav-api.yml';
@@ -59,26 +55,10 @@ class Template extends React.Component {
5955
{name: 'keywords', content: 'web, light, javascript, react, ssr'},
6056
]}
6157
/>
62-
<Header>
63-
<PageWidth>
64-
<FlexContainer>
65-
<FlexItem>
66-
<H1>
67-
<Link to="/" style={{backgroundColor: 'transparent'}}>
68-
<HeaderTitle>Fusion.js</HeaderTitle>
69-
</Link>
70-
</H1>
71-
</FlexItem>
72-
<FlexItem>
73-
<MainNav
74-
data={[docsContents, apiContents]}
75-
location={location}
76-
pathPrefix={pathPrefix}
77-
/>
78-
</FlexItem>
79-
</FlexContainer>
80-
</PageWidth>
81-
</Header>
58+
<PageHeader
59+
location={location}
60+
pathPrefix={pathPrefix}
61+
/>
8262
<Body>
8363
<PageWidth>
8464
<FlexContainer>

0 commit comments

Comments
 (0)