Skip to content

Commit b2d8143

Browse files
AndreycoMorgan Pretty
authored andcommitted
Improve Docs navigation on handheld devices.
Summary: Fixes facebook#7519 JS detects handheld device by sniffing UA string (very primitive detection). If on handheld device, event listener is registered. Event handler toggles Docs Navigation overlay after clicking on "Docs" nav button. Original Docs Navigation panel is taken out of the natural page flow using pure CSS and is styled to look "good" on device. As a result of this, Navigation overlay is ONLY visible when you are at Docs page, otherwise "Docs" nav button takes you Docs page first. iPhone/iPad previews ![iphone](https://cloud.githubusercontent.com/assets/829963/15409630/f1a64b1a-1e15-11e6-92eb-f85c5cd06754.gif) ![ipad](https://cloud.githubusercontent.com/assets/829963/15409631/f1a6f952-1e15-11e6-8f5c-6f89f54e6814.gif) Closes facebook#7640 Differential Revision: D3325440 Pulled By: vjeux fbshipit-source-id: a06b21d743d56bfea5db5b750836856c3af9bbe2
1 parent b007a96 commit b2d8143

File tree

4 files changed

+133
-38
lines changed

4 files changed

+133
-38
lines changed

website/core/DocsSidebar.js

Lines changed: 21 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -69,32 +69,31 @@ var DocsSidebar = React.createClass({
6969
},
7070

7171
getLink: function(metadata) {
72-
if (metadata.permalink.match(/^https?:/)) {
73-
return metadata.permalink;
74-
}
75-
return metadata.permalink + '#content';
72+
return metadata.permalink;
7673
},
7774

7875
render: function() {
7976
return <div className="nav-docs">
80-
{this.getCategories().map((category) =>
81-
<div className="nav-docs-section" key={category.name}>
82-
<h3>{category.name}</h3>
83-
<ul>
84-
{category.links.map((metadata) =>
85-
<li key={metadata.id}>
86-
<a
87-
target={metadata.permalink.match(/^https?:/) && '_blank'}
88-
style={{marginLeft: metadata.indent ? 20 : 0}}
89-
className={metadata.id === this.props.metadata.id ? 'active' : ''}
90-
href={this.getLink(metadata)}>
91-
{metadata.title}
92-
</a>
93-
</li>
94-
)}
95-
</ul>
96-
</div>
97-
)}
77+
<div className="nav-docs-viewport">
78+
{this.getCategories().map((category) =>
79+
<div className="nav-docs-section" key={category.name}>
80+
<h3>{category.name}</h3>
81+
<ul>
82+
{category.links.map((metadata) =>
83+
<li key={metadata.id}>
84+
<a
85+
target={metadata.permalink.match(/^https?:/) && '_blank'}
86+
style={{marginLeft: metadata.indent ? 20 : 0}}
87+
className={metadata.id === this.props.metadata.id ? 'active' : ''}
88+
href={this.getLink(metadata)}>
89+
{metadata.title}
90+
</a>
91+
</li>
92+
)}
93+
</ul>
94+
</div>
95+
)}
96+
</div>
9897
</div>;
9998
}
10099
});

website/core/HeaderLinks.js

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ var AlgoliaDocSearch = require('AlgoliaDocSearch');
1414

1515
var HeaderLinks = React.createClass({
1616
linksInternal: [
17-
{section: 'docs', href: 'docs/getting-started.html', text: 'Docs'},
17+
{section: 'docs', href: 'docs/getting-started.html', text: 'Docs', target: '.nav-docs'},
1818
{section: 'support', href: 'support.html', text: 'Support'},
1919
{section: 'showcase', href: 'showcase.html', text: 'Showcase'},
2020
{section: 'blog', href: 'blog/', text: 'Blog'},
@@ -30,7 +30,8 @@ var HeaderLinks = React.createClass({
3030
<li key={link.section}>
3131
<a
3232
href={link.href}
33-
className={link.section === this.props.section ? 'active' : ''}>
33+
className={link.section === this.props.section ? 'active' : ''}
34+
data-target={link.target}>
3435
{link.text}
3536
</a>
3637
</li>

website/src/react-native/css/react-native.css

Lines changed: 91 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -481,6 +481,92 @@ h1:hover .hash-link, h2:hover .hash-link, h3:hover .hash-link, h4:hover .hash-li
481481
border-bottom: 0;
482482
}
483483

484+
@media screen and (max-device-width: 960px) {
485+
.nav-docs {
486+
position: fixed;
487+
z-index: 90;
488+
top: 0;
489+
left: 0;
490+
width: 100%;
491+
height: 100%;
492+
margin: 0;
493+
padding: 53px 0 0 0;
494+
background: #3B3738;
495+
/* Transition these properties */
496+
transition: opacity 0.3s, visibility 0.3s;
497+
visibility: hidden;
498+
opacity: 0;
499+
}
500+
501+
.nav-docs-viewport {
502+
border-top: 1px solid rgb(5, 165, 209);
503+
height: 100%;
504+
padding: 25px;
505+
overflow: scroll;
506+
-webkit-overflow-scrolling: touch;
507+
top: -30px;
508+
position: relative;
509+
transition: top 0.3s;
510+
}
511+
512+
/* Active state */
513+
.nav-docs.in {
514+
visibility: visible;
515+
opacity: 1;
516+
}
517+
518+
.nav-docs.in .nav-docs-viewport {
519+
top: 0;
520+
}
521+
522+
.nav-docs * {
523+
-webkit-font-smoothing: antialiased;
524+
}
525+
526+
.nav-docs-section + .nav-docs-section {
527+
margin-top: 50px;
528+
}
529+
530+
.nav-docs-section li {
531+
margin: 5px 0;
532+
}
533+
534+
.nav-docs-section h3,
535+
.nav-docs-section a {
536+
color: white;
537+
}
538+
539+
.nav-docs-section h3 {
540+
border-bottom: 1px solid white;
541+
margin-bottom: 10px;
542+
opacity: 0.3;
543+
}
544+
545+
.nav-docs-section a {
546+
margin-right: 25px;
547+
font-size: 120%;
548+
padding: 5px 0;
549+
}
550+
551+
.nav-docs-section a.active {
552+
border-bottom-style: solid;
553+
border-bottom-width: 1px;
554+
color: rgb(5, 165, 209);
555+
}
556+
}
557+
558+
@media screen and (min-device-width: 641px) and (max-device-width: 1024px) {
559+
.nav-docs-section ul {
560+
display: flex;
561+
flex-wrap: wrap;
562+
}
563+
564+
/* Display 2 columns on tablet */
565+
.nav-docs-section li {
566+
width: 50%;
567+
}
568+
}
569+
484570
.nav-blog li {
485571
margin-bottom: 5px;
486572
}
@@ -999,13 +1085,13 @@ small code, li code, p code {
9991085
outline: none;
10001086
}
10011087

1002-
@media screen and (max-width: 960px) {
1003-
.nav-main {
1004-
position: static;
1088+
@media screen and (max-width: 680px) {
1089+
.container {
1090+
padding-top: 100px;
10051091
}
10061092

1007-
.container {
1008-
padding-top: 0;
1093+
.nav-docs {
1094+
padding-top: 103px;
10091095
}
10101096
}
10111097

@@ -1345,15 +1431,6 @@ div[data-twttr-id] iframe {
13451431
border: none;
13461432
padding: 0;
13471433
}
1348-
.nav-docs h3 {
1349-
margin: 0;
1350-
}
1351-
.nav-docs {
1352-
float: none;
1353-
width: auto;
1354-
margin-top: -8px;
1355-
margin-bottom: 20px;
1356-
}
13571434
h1 {
13581435
font-size: 30px;
13591436
line-height: 30px;

website/src/react-native/js/scripts.js

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,10 @@
77
document.addEventListener('DOMContentLoaded', init);
88

99
function init() {
10+
if (isMobile()) {
11+
document.querySelector('.nav-site-wrapper a[data-target]').addEventListener('click', toggleTargetNav);
12+
}
13+
1014
var backdrop = document.querySelector('.modal-backdrop');
1115
if (!backdrop) return;
1216

@@ -42,4 +46,18 @@
4246
modal.classList.remove('modal-open');
4347
}
4448

49+
function toggleTargetNav(event) {
50+
var target = document.body.querySelector(event.target.getAttribute('data-target'));
51+
52+
if (target) {
53+
event.preventDefault();
54+
target.classList.toggle('in');
55+
}
56+
}
57+
58+
// Primitive mobile detection
59+
function isMobile() {
60+
return ( /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent) );
61+
}
62+
4563
}());

0 commit comments

Comments
 (0)