Skip to content

Commit e7ee214

Browse files
authored
Merge pull request #384 from webpack/feature/swipable-menu-from-366
Swipable Menu (From #366)
2 parents eaec9ba + 655f02c commit e7ee214

File tree

2 files changed

+103
-12
lines changed

2 files changed

+103
-12
lines changed

components/sidebar-mobile/sidebar-mobile-style.scss

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,25 +3,45 @@
33

44
.sidebar-mobile {
55
position: fixed;
6-
width: 280px;
6+
width: 295px;
77
height: 100vh;
88
z-index: 100;
99
top: 0;
1010
overflow-y: auto;
1111
overflow-x: hidden;
1212
-webkit-overflow-scrolling: touch;
13-
background: getColor(white);
1413
transform: translate3D(-100%, 0, 0);
14+
transform: translate3D(calc(-100% + 5px), 0, 0);
1515
transition: all 500ms;
1616

1717
@include break {
1818
display: none;
1919
}
20-
20+
2121
&--visible {
2222
transform: translate3D(0, 0, 0);
23-
box-shadow: 0 0 5px getColor(emperor);
2423
}
24+
25+
&.no-delay{
26+
transition-duration: 0ms;
27+
}
28+
}
29+
30+
.sidebar-mobile__toggle {
31+
position: absolute;
32+
top: 45px;
33+
bottom: 0;
34+
width: 32px;
35+
left: 285px;
36+
}
37+
38+
.sidebar-mobile__content {
39+
position: relative;
40+
width: 285px;
41+
height: 100vh;
42+
overflow-x: hidden;
43+
background: getColor(white);
44+
box-shadow: 0 0 5px getColor(emperor);
2545
}
2646

2747
.sidebar-mobile__close {

components/sidebar-mobile/sidebar-mobile.jsx

Lines changed: 79 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,9 @@ import React from 'react';
22
import Link from '../link/link';
33
import './sidebar-mobile-style';
44

5+
let initialTouchPosition = {};
6+
let lastTouchPosition = {};
7+
58
export default class SidebarMobile extends React.Component {
69
constructor(props) {
710
super(props);
@@ -11,11 +14,26 @@ export default class SidebarMobile extends React.Component {
1114

1215
render() {
1316
return (
14-
<nav className="sidebar-mobile" ref={ ref => this.container = ref }>
15-
<i className="sidebar-mobile__close icon-cross"
16-
onClick={ this._close.bind(this) } />
17+
<nav
18+
className="sidebar-mobile"
19+
ref={ ref => this.container = ref }
20+
onTouchStart={this._handleTouchStart.bind(this)}
21+
onTouchMove={this._handleTouchMove.bind(this)}
22+
onTouchEnd={this._handleTouchEnd.bind(this)}>
23+
24+
<div
25+
className="sidebar-mobile__toggle"
26+
onTouchStart={this._handleTouchStart.bind(this)}
27+
onTouchMove={this._handleOpenerTouchMove.bind(this)}
28+
onTouchEnd={this._handleTouchEnd.bind(this)} />
1729

18-
{ this._getSections() }
30+
<div className="sidebar-mobile__content">
31+
<i
32+
className="sidebar-mobile__close icon-cross"
33+
onClick={ this._close.bind(this) } />
34+
35+
{ this._getSections() }
36+
</div>
1937
</nav>
2038
);
2139
}
@@ -42,7 +60,7 @@ export default class SidebarMobile extends React.Component {
4260
_getSections() {
4361
return this.props.sections.map(section => (
4462
<div key={ section.url }>
45-
<h3 className="sidebar-mobile__section">{ section.title }</h3>
63+
<h3 className='sidebar-mobile__section'>{ section.title }</h3>
4664
{ this._getPages(section.pages) }
4765
</div>
4866
));
@@ -70,8 +88,7 @@ export default class SidebarMobile extends React.Component {
7088
key={ url }
7189
className={ `sidebar-mobile__page ${active ? 'sidebar-mobile__page--active' : ''}` }
7290
to={ url }
73-
onClick={ this._close.bind(this) }
74-
>
91+
onClick={ this._close.bind(this) }>
7592
{ page.title }
7693
</Link>
7794
);
@@ -101,4 +118,58 @@ export default class SidebarMobile extends React.Component {
101118
'sidebar-mobile--visible'
102119
);
103120
}
104-
}
121+
122+
_open() {
123+
this.container.classList.add(
124+
'sidebar-mobile--visible'
125+
);
126+
}
127+
128+
_handleTouchStart(e){
129+
initialTouchPosition.x = e.touches[0].pageX;
130+
initialTouchPosition.y = e.touches[0].pageY;
131+
132+
// For instant transform along with the touch
133+
this.container.classList.add('no-delay');
134+
}
135+
136+
_handleTouchMove(e){
137+
let xDiff = initialTouchPosition.x - e.touches[0].pageX;
138+
let yDiff = initialTouchPosition.y - e.touches[0].pageY;
139+
let factor = Math.abs(yDiff / xDiff);
140+
141+
// Factor makes sure horizontal and vertical scroll dont take place together
142+
if (xDiff>0 && factor < 0.8) {
143+
e.preventDefault();
144+
this.container.style.transform = `translateX(-${xDiff}px)`;
145+
lastTouchPosition.x = e.touches[0].pageX;
146+
lastTouchPosition.y = e.touches[0].pageY;
147+
}
148+
}
149+
150+
_handleOpenerTouchMove(e){
151+
let xDiff = e.touches[0].pageX - initialTouchPosition.x;
152+
let yDiff = initialTouchPosition.y - e.touches[0].pageY;
153+
let factor = Math.abs(yDiff / xDiff);
154+
155+
// Factor makes sure horizontal and vertical scroll dont take place together
156+
if (xDiff > 0 && xDiff < 295 && factor < 0.8) {
157+
e.preventDefault();
158+
this.container.style.transform = `translateX(calc(-100% + ${xDiff}px))`;
159+
lastTouchPosition.x = e.touches[0].pageX;
160+
lastTouchPosition.y = e.touches[0].pageY;
161+
}
162+
}
163+
164+
_handleTouchEnd(e){
165+
// Free up all the inline styling
166+
this.container.classList.remove('no-delay');
167+
this.container.style = '';
168+
169+
if (initialTouchPosition.x - lastTouchPosition.x > 100) {
170+
this._close();
171+
} else if (lastTouchPosition.x - initialTouchPosition.x > 100) {
172+
this._open();
173+
}
174+
}
175+
}

0 commit comments

Comments
 (0)