From ffc4483cd7486cb8fda5dded1af5c719401ada77 Mon Sep 17 00:00:00 2001 From: Andrej Badin Date: Thu, 19 May 2016 22:59:51 +0200 Subject: [PATCH] Improve Docs navigation on handheld devices. Summary: 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. --- website/core/DocsSidebar.js | 43 ++++--- website/core/HeaderLinks.js | 5 +- website/src/react-native/css/react-native.css | 105 +++++++++++++++--- website/src/react-native/js/scripts.js | 18 +++ 4 files changed, 133 insertions(+), 38 deletions(-) diff --git a/website/core/DocsSidebar.js b/website/core/DocsSidebar.js index d8640e40d7908c..7b643aba98d79d 100644 --- a/website/core/DocsSidebar.js +++ b/website/core/DocsSidebar.js @@ -69,32 +69,31 @@ var DocsSidebar = React.createClass({ }, getLink: function(metadata) { - if (metadata.permalink.match(/^https?:/)) { - return metadata.permalink; - } - return metadata.permalink + '#content'; + return metadata.permalink; }, render: function() { return
- {this.getCategories().map((category) => -
-

{category.name}

- -
- )} +
+ {this.getCategories().map((category) => +
+

{category.name}

+ +
+ )} +
; } }); diff --git a/website/core/HeaderLinks.js b/website/core/HeaderLinks.js index b5dbffde94262c..2cb72850be8d84 100644 --- a/website/core/HeaderLinks.js +++ b/website/core/HeaderLinks.js @@ -14,7 +14,7 @@ var AlgoliaDocSearch = require('AlgoliaDocSearch'); var HeaderLinks = React.createClass({ linksInternal: [ - {section: 'docs', href: 'docs/getting-started.html', text: 'Docs'}, + {section: 'docs', href: 'docs/getting-started.html', text: 'Docs', target: '.nav-docs'}, {section: 'support', href: 'support.html', text: 'Support'}, {section: 'showcase', href: 'showcase.html', text: 'Showcase'}, {section: 'blog', href: 'blog/', text: 'Blog'}, @@ -30,7 +30,8 @@ var HeaderLinks = React.createClass({
  • + className={link.section === this.props.section ? 'active' : ''} + data-target={link.target}> {link.text}
  • diff --git a/website/src/react-native/css/react-native.css b/website/src/react-native/css/react-native.css index 8ba8d434a7e106..c768d8370e935d 100644 --- a/website/src/react-native/css/react-native.css +++ b/website/src/react-native/css/react-native.css @@ -481,6 +481,92 @@ h1:hover .hash-link, h2:hover .hash-link, h3:hover .hash-link, h4:hover .hash-li border-bottom: 0; } +@media screen and (max-device-width: 960px) { + .nav-docs { + position: fixed; + z-index: 90; + top: 0; + left: 0; + width: 100%; + height: 100%; + margin: 0; + padding: 53px 0 0 0; + background: #3B3738; + /* Transition these properties */ + transition: opacity 0.3s, visibility 0.3s; + visibility: hidden; + opacity: 0; + } + + .nav-docs-viewport { + border-top: 1px solid rgb(5, 165, 209); + height: 100%; + padding: 25px; + overflow: scroll; + -webkit-overflow-scrolling: touch; + top: -30px; + position: relative; + transition: top 0.3s; + } + + /* Active state */ + .nav-docs.in { + visibility: visible; + opacity: 1; + } + + .nav-docs.in .nav-docs-viewport { + top: 0; + } + + .nav-docs * { + -webkit-font-smoothing: antialiased; + } + + .nav-docs-section + .nav-docs-section { + margin-top: 50px; + } + + .nav-docs-section li { + margin: 5px 0; + } + + .nav-docs-section h3, + .nav-docs-section a { + color: white; + } + + .nav-docs-section h3 { + border-bottom: 1px solid white; + margin-bottom: 10px; + opacity: 0.3; + } + + .nav-docs-section a { + margin-right: 25px; + font-size: 120%; + padding: 5px 0; + } + + .nav-docs-section a.active { + border-bottom-style: solid; + border-bottom-width: 1px; + color: rgb(5, 165, 209); + } +} + +@media screen and (min-device-width: 641px) and (max-device-width: 1024px) { + .nav-docs-section ul { + display: flex; + flex-wrap: wrap; + } + + /* Display 2 columns on tablet */ + .nav-docs-section li { + width: 50%; + } +} + .nav-blog li { margin-bottom: 5px; } @@ -999,13 +1085,13 @@ small code, li code, p code { outline: none; } -@media screen and (max-width: 960px) { - .nav-main { - position: static; +@media screen and (max-width: 680px) { + .container { + padding-top: 100px; } - .container { - padding-top: 0; + .nav-docs { + padding-top: 103px; } } @@ -1345,15 +1431,6 @@ div[data-twttr-id] iframe { border: none; padding: 0; } - .nav-docs h3 { - margin: 0; - } - .nav-docs { - float: none; - width: auto; - margin-top: -8px; - margin-bottom: 20px; - } h1 { font-size: 30px; line-height: 30px; diff --git a/website/src/react-native/js/scripts.js b/website/src/react-native/js/scripts.js index 9bed77965b3cdd..0932c31ff18130 100644 --- a/website/src/react-native/js/scripts.js +++ b/website/src/react-native/js/scripts.js @@ -7,6 +7,10 @@ document.addEventListener('DOMContentLoaded', init); function init() { + if (isMobile()) { + document.querySelector('.nav-site-wrapper a[data-target]').addEventListener('click', toggleTargetNav); + } + var backdrop = document.querySelector('.modal-backdrop'); if (!backdrop) return; @@ -42,4 +46,18 @@ modal.classList.remove('modal-open'); } + function toggleTargetNav(event) { + var target = document.body.querySelector(event.target.getAttribute('data-target')); + + if (target) { + event.preventDefault(); + target.classList.toggle('in'); + } + } + + // Primitive mobile detection + function isMobile() { + return ( /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent) ); + } + }());