mirror of
https://github.com/danbulant/api_docs
synced 2026-05-24 12:27:29 +00:00
Add retracting sidebar for tablets
This commit is contained in:
parent
ec9a688846
commit
c2c35cfa25
6 changed files with 246 additions and 1 deletions
BIN
source/images/navbar.png
Normal file
BIN
source/images/navbar.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 150 B |
|
|
@ -7,6 +7,11 @@
|
||||||
$(toc);
|
$(toc);
|
||||||
$(animate);
|
$(animate);
|
||||||
|
|
||||||
|
var closeToc = function() {
|
||||||
|
$(".tocify-wrapper").removeClass('open');
|
||||||
|
$("#nav-button").removeClass('open');
|
||||||
|
};
|
||||||
|
|
||||||
function toc () {
|
function toc () {
|
||||||
toc = $("#toc").tocify({
|
toc = $("#toc").tocify({
|
||||||
selectors: 'h1, h2',
|
selectors: 'h1, h2',
|
||||||
|
|
@ -23,6 +28,15 @@
|
||||||
return element.prop('id');
|
return element.prop('id');
|
||||||
}
|
}
|
||||||
}).data('toc-tocify');
|
}).data('toc-tocify');
|
||||||
|
|
||||||
|
$("#nav-button").click(function() {
|
||||||
|
$(".tocify-wrapper").toggleClass('open');
|
||||||
|
$("#nav-button").toggleClass('open');
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
|
||||||
|
$(".page-wrapper").click(closeToc);
|
||||||
|
$(".tocify-item").click(closeToc);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Hack to make already open sections to start opened,
|
// Hack to make already open sections to start opened,
|
||||||
|
|
|
||||||
169
source/javascripts/lib/energize.js
Normal file
169
source/javascripts/lib/energize.js
Normal file
|
|
@ -0,0 +1,169 @@
|
||||||
|
/**
|
||||||
|
* energize.js v0.1.0
|
||||||
|
*
|
||||||
|
* Speeds up click events on mobile devices.
|
||||||
|
* https://github.com/davidcalhoun/energize.js
|
||||||
|
*/
|
||||||
|
|
||||||
|
(function() { // Sandbox
|
||||||
|
/**
|
||||||
|
* Don't add to non-touch devices, which don't need to be sped up
|
||||||
|
*/
|
||||||
|
if(!('ontouchstart' in window)) return;
|
||||||
|
|
||||||
|
var lastClick = {},
|
||||||
|
isThresholdReached, touchstart, touchmove, touchend,
|
||||||
|
click, closest;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* isThresholdReached
|
||||||
|
*
|
||||||
|
* Compare touchstart with touchend xy coordinates,
|
||||||
|
* and only fire simulated click event if the coordinates
|
||||||
|
* are nearby. (don't want clicking to be confused with a swipe)
|
||||||
|
*/
|
||||||
|
isThresholdReached = function(startXY, xy) {
|
||||||
|
return Math.abs(startXY[0] - xy[0]) > 5 || Math.abs(startXY[1] - xy[1]) > 5;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* touchstart
|
||||||
|
*
|
||||||
|
* Save xy coordinates when the user starts touching the screen
|
||||||
|
*/
|
||||||
|
touchstart = function(e) {
|
||||||
|
this.startXY = [e.touches[0].clientX, e.touches[0].clientY];
|
||||||
|
this.threshold = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* touchmove
|
||||||
|
*
|
||||||
|
* Check if the user is scrolling past the threshold.
|
||||||
|
* Have to check here because touchend will not always fire
|
||||||
|
* on some tested devices (Kindle Fire?)
|
||||||
|
*/
|
||||||
|
touchmove = function(e) {
|
||||||
|
// NOOP if the threshold has already been reached
|
||||||
|
if(this.threshold) return false;
|
||||||
|
|
||||||
|
this.threshold = isThresholdReached(this.startXY, [e.touches[0].clientX, e.touches[0].clientY]);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* touchend
|
||||||
|
*
|
||||||
|
* If the user didn't scroll past the threshold between
|
||||||
|
* touchstart and touchend, fire a simulated click.
|
||||||
|
*
|
||||||
|
* (This will fire before a native click)
|
||||||
|
*/
|
||||||
|
touchend = function(e) {
|
||||||
|
// Don't fire a click if the user scrolled past the threshold
|
||||||
|
if(this.threshold || isThresholdReached(this.startXY, [e.changedTouches[0].clientX, e.changedTouches[0].clientY])) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create and fire a click event on the target element
|
||||||
|
* https://developer.mozilla.org/en/DOM/event.initMouseEvent
|
||||||
|
*/
|
||||||
|
var touch = e.changedTouches[0],
|
||||||
|
evt = document.createEvent('MouseEvents');
|
||||||
|
evt.initMouseEvent('click', true, true, window, 0, touch.screenX, touch.screenY, touch.clientX, touch.clientY, false, false, false, false, 0, null);
|
||||||
|
evt.simulated = true; // distinguish from a normal (nonsimulated) click
|
||||||
|
e.target.dispatchEvent(evt);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* click
|
||||||
|
*
|
||||||
|
* Because we've already fired a click event in touchend,
|
||||||
|
* we need to listed for all native click events here
|
||||||
|
* and suppress them as necessary.
|
||||||
|
*/
|
||||||
|
click = function(e) {
|
||||||
|
/**
|
||||||
|
* Prevent ghost clicks by only allowing clicks we created
|
||||||
|
* in the click event we fired (look for e.simulated)
|
||||||
|
*/
|
||||||
|
var time = Date.now(),
|
||||||
|
timeDiff = time - lastClick.time,
|
||||||
|
x = e.clientX,
|
||||||
|
y = e.clientY,
|
||||||
|
xyDiff = [Math.abs(lastClick.x - x), Math.abs(lastClick.y - y)],
|
||||||
|
target = closest(e.target, 'A') || e.target, // needed for standalone apps
|
||||||
|
nodeName = target.nodeName,
|
||||||
|
isLink = nodeName === 'A',
|
||||||
|
standAlone = window.navigator.standalone && isLink && e.target.getAttribute("href");
|
||||||
|
|
||||||
|
lastClick.time = time;
|
||||||
|
lastClick.x = x;
|
||||||
|
lastClick.y = y;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unfortunately Android sometimes fires click events without touch events (seen on Kindle Fire),
|
||||||
|
* so we have to add more logic to determine the time of the last click. Not perfect...
|
||||||
|
*
|
||||||
|
* Older, simpler check: if((!e.simulated) || standAlone)
|
||||||
|
*/
|
||||||
|
if((!e.simulated && (timeDiff < 500 || (timeDiff < 1500 && xyDiff[0] < 50 && xyDiff[1] < 50))) || standAlone) {
|
||||||
|
e.preventDefault();
|
||||||
|
e.stopPropagation();
|
||||||
|
if(!standAlone) return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Special logic for standalone web apps
|
||||||
|
* See http://stackoverflow.com/questions/2898740/iphone-safari-web-app-opens-links-in-new-window
|
||||||
|
*/
|
||||||
|
if(standAlone) {
|
||||||
|
window.location = target.getAttribute("href");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add an energize-focus class to the targeted link (mimics :focus behavior)
|
||||||
|
* TODO: test and/or remove? Does this work?
|
||||||
|
*/
|
||||||
|
if(!target || !target.classList) return;
|
||||||
|
target.classList.add("energize-focus");
|
||||||
|
window.setTimeout(function(){
|
||||||
|
target.classList.remove("energize-focus");
|
||||||
|
}, 150);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* closest
|
||||||
|
* @param {HTMLElement} node current node to start searching from.
|
||||||
|
* @param {string} tagName the (uppercase) name of the tag you're looking for.
|
||||||
|
*
|
||||||
|
* Find the closest ancestor tag of a given node.
|
||||||
|
*
|
||||||
|
* Starts at node and goes up the DOM tree looking for a
|
||||||
|
* matching nodeName, continuing until hitting document.body
|
||||||
|
*/
|
||||||
|
closest = function(node, tagName){
|
||||||
|
var curNode = node;
|
||||||
|
|
||||||
|
while(curNode !== document.body) { // go up the dom until we find the tag we're after
|
||||||
|
if(!curNode || curNode.nodeName === tagName) { return curNode; } // found
|
||||||
|
curNode = curNode.parentNode; // not found, so keep going up
|
||||||
|
}
|
||||||
|
|
||||||
|
return null; // not found
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add all delegated event listeners
|
||||||
|
*
|
||||||
|
* All the events we care about bubble up to document,
|
||||||
|
* so we can take advantage of event delegation.
|
||||||
|
*
|
||||||
|
* Note: no need to wait for DOMContentLoaded here
|
||||||
|
*/
|
||||||
|
document.addEventListener('touchstart', touchstart, false);
|
||||||
|
document.addEventListener('touchmove', touchmove, false);
|
||||||
|
document.addEventListener('touchend', touchend, false);
|
||||||
|
document.addEventListener('click', click, true); // TODO: why does this use capture?
|
||||||
|
|
||||||
|
})();
|
||||||
|
|
@ -19,6 +19,7 @@ under the License.
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
<meta content="IE=edge,chrome=1" http-equiv="X-UA-Compatible">
|
<meta content="IE=edge,chrome=1" http-equiv="X-UA-Compatible">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
|
||||||
<title><%= current_page.data.title || "API Documentation" %></title>
|
<title><%= current_page.data.title || "API Documentation" %></title>
|
||||||
|
|
||||||
<%= stylesheet_link_tag :screen, media: :screen %>
|
<%= stylesheet_link_tag :screen, media: :screen %>
|
||||||
|
|
@ -40,6 +41,10 @@ under the License.
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body class="<%= page_classes %>">
|
<body class="<%= page_classes %>">
|
||||||
|
<a href="#" id="nav-button">
|
||||||
|
<%= image_tag('navbar.png') %>
|
||||||
|
<span>NAV</span>
|
||||||
|
</a>
|
||||||
<div class="tocify-wrapper">
|
<div class="tocify-wrapper">
|
||||||
<%= image_tag "logo.png" %>
|
<%= image_tag "logo.png" %>
|
||||||
<% if current_page.data.search %>
|
<% if current_page.data.search %>
|
||||||
|
|
|
||||||
|
|
@ -34,6 +34,7 @@ html, body {
|
||||||
@extend %default-font;
|
@extend %default-font;
|
||||||
background-color: $main-bg;
|
background-color: $main-bg;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
|
-webkit-text-size-adjust: none; /* Never autoresize text */
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
@ -41,9 +42,11 @@ html, body {
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
.tocify-wrapper {
|
.tocify-wrapper {
|
||||||
|
@include transition(width ease-in-out 0.3s);
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
overflow-x: hidden;
|
overflow-x: hidden;
|
||||||
position: fixed;
|
position: fixed;
|
||||||
|
z-index: 30;
|
||||||
top: 0;
|
top: 0;
|
||||||
left: 0;
|
left: 0;
|
||||||
bottom: 0;
|
bottom: 0;
|
||||||
|
|
@ -70,6 +73,7 @@ html, body {
|
||||||
width: $nav-width - 30;
|
width: $nav-width - 30;
|
||||||
outline: none;
|
outline: none;
|
||||||
color: $nav-text;
|
color: $nav-text;
|
||||||
|
border-radius: 0; /* ios has a default border radius */
|
||||||
}
|
}
|
||||||
|
|
||||||
&:before {
|
&:before {
|
||||||
|
|
@ -182,6 +186,35 @@ html, body {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// button to show navigation on mobile devices
|
||||||
|
#nav-button {
|
||||||
|
display: none;
|
||||||
|
position: fixed;
|
||||||
|
top: $main-padding / 2 - 8px;
|
||||||
|
left: $main-padding / 2 - 8px;
|
||||||
|
z-index: 100;
|
||||||
|
color: #000;
|
||||||
|
text-decoration: none;
|
||||||
|
font-weight: bold;
|
||||||
|
opacity: 0.7;
|
||||||
|
line-height: 16px;
|
||||||
|
img {
|
||||||
|
height: 16px;
|
||||||
|
}
|
||||||
|
span {
|
||||||
|
position: absolute;
|
||||||
|
top: 30px;
|
||||||
|
left: -0.4em;
|
||||||
|
line-height: 1;
|
||||||
|
@include transform(rotate(-90deg));
|
||||||
|
}
|
||||||
|
|
||||||
|
@include transition(left ease-in-out 0.3s);
|
||||||
|
|
||||||
|
&:hover { opacity: 1; }
|
||||||
|
&.open {left: $main-padding / 2 - 8px + $nav-width}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
// PAGE LAYOUT AND CODE SAMPLE BACKGROUND
|
// PAGE LAYOUT AND CODE SAMPLE BACKGROUND
|
||||||
|
|
@ -189,7 +222,6 @@ html, body {
|
||||||
|
|
||||||
.page-wrapper {
|
.page-wrapper {
|
||||||
margin-left: $nav-width;
|
margin-left: $nav-width;
|
||||||
min-width: 700px;
|
|
||||||
position: relative;
|
position: relative;
|
||||||
z-index: 10;
|
z-index: 10;
|
||||||
background-color: $main-bg;
|
background-color: $main-bg;
|
||||||
|
|
@ -488,3 +520,26 @@ html, body {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// RESPONSIVE DESIGN
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// These are the styles for phones and tablets
|
||||||
|
|
||||||
|
@media (max-width: $tablet-width) {
|
||||||
|
.tocify-wrapper {
|
||||||
|
width: 0;
|
||||||
|
|
||||||
|
&.open {
|
||||||
|
width: $nav-width;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.page-wrapper {
|
||||||
|
margin-left: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#nav-button {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -60,6 +60,8 @@ $nav-padding: 15px; // padding to left and right of navbar
|
||||||
$nav-indent: 10px; // extra padding for ToC subitems
|
$nav-indent: 10px; // extra padding for ToC subitems
|
||||||
$code-annotation-padding: 13px; // padding inside code annotations
|
$code-annotation-padding: 13px; // padding inside code annotations
|
||||||
$h1-margin-bottom: 21px; // padding under the largest header tags
|
$h1-margin-bottom: 21px; // padding under the largest header tags
|
||||||
|
$tablet-width: 930px; // min width before reverting to tablet size
|
||||||
|
$phone-width: $tablet-width - $nav-width; // min width before reverting to mobile size
|
||||||
|
|
||||||
|
|
||||||
// FONTS
|
// FONTS
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue