├── .gitignore ├── Makefile ├── README.md ├── addons.js ├── bower.json ├── bower_components └── jquery-scrollspy │ ├── .eslintrc │ ├── .gitignore │ ├── README.md │ ├── bower.json │ ├── examples │ ├── colors.html │ └── fixednav.html │ ├── gulpfile.js │ ├── jquery-scrollspy.js │ ├── jquery-scrollspy.min.js │ ├── package.json │ └── test │ ├── demo.html │ ├── memory-leak.coffee │ └── memory-leak.js ├── docs ├── AZURE.md ├── CAYENNEAPI.md ├── CUSTOMWIDGETS.md ├── DOWNLOADS.md ├── FEATURES.md ├── GETTINGSTARTED.md ├── INTRO.md ├── IOTREADY.md ├── LORA.md ├── MQTTAPIS.md ├── SKETCHFILES.md ├── SUPPORTEDHARDWARE.md └── TINA.md ├── examples ├── MQTT_EthernetShieldW5100_with_TMP36 │ └── MQTT_EthernetShieldW5100_with_TMP36.ino └── README.md ├── flatdoc.js ├── img ├── expand.png └── toggle.png ├── index.html ├── legacy.js ├── package.json ├── scrollspy.min.js ├── support ├── Notes.md ├── blur.jpg ├── dox2md.js ├── legacy-header.js ├── preview.jpg ├── theme.css ├── theme.js └── vendor │ ├── Makefile │ ├── html5shiv.js │ ├── jquery.fillsize.js │ ├── jquery.js │ ├── jquery.smartquotes.js │ └── respond.js └── theme-white ├── navbar-default.css ├── navbar.css ├── script.js ├── style.css └── style.styl /.gitignore: -------------------------------------------------------------------------------- 1 | .idea/ 2 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | UGLIFY := ./node_modules/.bin/uglifyjs --comments "/^!/" 2 | STYLUS := ./node_modules/.bin/stylus -U -u nib 3 | DOX := ./node_modules/.bin/dox 4 | 5 | all: \ 6 | legacy.js \ 7 | theme-white/style.css \ 8 | theme-white/script.js \ 9 | Reference.md 10 | 11 | watch: 12 | while true; do make all | grep -v "Nothing"; sleep 1; done 13 | 14 | # Legacy shims for IE 15 | legacy.js: \ 16 | support/legacy-header.js \ 17 | support/vendor/html5shiv.js \ 18 | support/vendor/respond.js 19 | cat $^ > $@ 20 | 21 | %.css: %.styl 22 | (echo "/*\n\nPlease don't edit this file directly.\nInstead, edit the stylus (.styl) files and compile it to CSS on your machine.\n\n*/" ; $(STYLUS) < $<) > $@ 23 | 24 | Reference.md: flatdoc.js 25 | $(DOX) -r < $< | node support/dox2md.js --default-level 3 > $@ 26 | 27 | # $ make v/0.1.0 28 | # Makes a distribution. 29 | # 30 | v/%: all 31 | mkdir -p $@ 32 | $(UGLIFY) < flatdoc.js > $@/flatdoc.js 33 | $(UGLIFY) < legacy.js > $@/legacy.js 34 | cp -R templates $@/templates 35 | mkdir -p $@/theme-white 36 | cp theme-white/style.css $@/theme-white 37 | cp theme-white/script.js $@/theme-white 38 | 39 | .PHONY: watch 40 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Welcome to the Cayenne Docs 2 | 3 | ## Introduction 4 | I will be walking you through editing content from Cayenne's boutiful Documentation setup. This is a work-in-progress, and collaboration is always encouraged. 5 | 6 | 7 | ## Important Links 8 | Markdown Cheatsheet (the syntax we will be using)
9 | https://github.com/adam-p/markdown-here/wiki/Markdown-Cheatsheet 10 | 11 | MacDown (Markdown editor for Mac)
12 | http://macdown.uranusjr.com/ 13 | 14 | 15 | ## Getting Started 16 | This section will highlight the common actions you might take while editing the docs. The instructions below describe the process using GitHub's built-in web editor. 17 | 18 | ### Switching to the Staging version 19 | Are you looking for the Staging version of the Docs? On the main repo page, right above the files, select the dropdown labeled Branch. From there, select the Staging branch. You are now in the Staging version of the Docs. 20 | 21 | ### Making a text edit 22 | Let's say you find something incorrectly written or you would like to update some text. First, you would find the main section the article is located in. 23 | 24 | **We'll use Getting Started for our example:** 25 | 26 | 1. Navigate to the Home directory of the repo by clicking cayenne-docs at the top of the page. 27 | 2. Then, select the docs directory by clicking the link. 28 | 3. In that folder, you will see the various high-level sections of the Docs. Select the GETTINGSTARTED.md by clicking it. 29 | 4. You will now see a preview of this section. Above the preview, on the grey bar, you will see a pencil icon. Click that to begin editing. 30 | 5. Find the portion of text you would like to edit. Make your changes, and then preview them by selecting the eye icon labeled "Preview changes". 31 | 6. Once you are satisfied with the results, click Commit changes. 32 | *(If you want to add some style, code, or specialized text, follow the link to the [Markdown Cheatsheet](https://github.com/adam-p/markdown-here/wiki/Markdown-Cheatsheet) for a quick breakdown. If you want to add an image, follow the steps listed below.)* 33 | 34 | **Image Example Code** 35 | ``` 36 | 37 |


ALT

38 | 39 | ``` 40 | 41 | ### I need to add more anchor links, is there sample code for this? 42 | If you need to add additional anchor links to a section in the Docs, use the sample code below and fill in the anchor link (e.g. #apis) without the # sign. 43 | 44 | **In this example, we're linking to a fictional #help-me section** 45 | ``` 46 | 47 | 48 | 49 | ``` 50 | 51 | **Sample code for copy + pasting purposes** 52 | ``` 53 | 54 | 55 | 56 | ``` -------------------------------------------------------------------------------- /addons.js: -------------------------------------------------------------------------------- 1 | (function($) { 2 | var $window = $(window); 3 | var $document = $(document); 4 | 5 | $document.on('flatdoc:ready', function() { 6 | 7 | $("a.active").closest("ul.level-2").slideToggle("slow"); 8 | 9 | //Introduction navigation 10 | var introi = $("li#introduction-item"); 11 | var introl = $("ul#introduction-list"); 12 | 13 | introi.prepend( $("
") ); 14 | introl.hide(); 15 | var introe = $("#introduction-item > div.toggle-menu"); 16 | 17 | introe.click(function(){ 18 | $(this).toggleClass("expand"); 19 | introl.slideToggle("slow"); 20 | 21 | }); 22 | 23 | //Downloads navigation 24 | var dli = $("li#downloads-item"); 25 | var dll = $("ul#downloads-list"); 26 | 27 | dli.prepend( $("
") ); 28 | dll.hide(); 29 | var dle = $("#downloads-item > div.toggle-menu"); 30 | 31 | dle.click(function(){ 32 | $(this).toggleClass("expand"); 33 | dll.slideToggle("slow"); 34 | 35 | }); 36 | 37 | //Getting Started navigation 38 | var gsi = $("li#getting-started-item"); 39 | var gsl = $("ul#getting-started-list"); 40 | 41 | gsi.prepend( $("
") ); 42 | gsl.hide(); 43 | var gse = $("#getting-started-item > div.toggle-menu"); 44 | 45 | gse.click(function(){ 46 | $(this).toggleClass("expand"); 47 | gsl.slideToggle("slow"); 48 | 49 | }); 50 | 51 | //Features navigation 52 | var fei = $("li#features-item"); 53 | var fel = $("ul#features-list"); 54 | 55 | fei.prepend( $("
") ); 56 | fel.hide(); 57 | var fee = $("#features-item > div.toggle-menu"); 58 | 59 | fee.click(function(){ 60 | $(this).toggleClass("expand"); 61 | fel.slideToggle("slow"); 62 | 63 | }); 64 | 65 | 66 | //Custom Widgets navigation 67 | var cwi = $("li#custom-widgets-item"); 68 | var cwl = $("ul#custom-widgets-list"); 69 | 70 | cwi.prepend( $("
") ); 71 | cwl.hide(); 72 | var cwe = $("#custom-widgets-item > div.toggle-menu"); 73 | 74 | cwe.click(function(){ 75 | $(this).toggleClass("expand"); 76 | cwl.slideToggle("slow"); 77 | 78 | }); 79 | 80 | //Sketch Files navigation 81 | var sfi = $("li#sketch-files-item"); 82 | var sfl = $("ul#sketch-files-list"); 83 | 84 | sfi.prepend( $("
") ); 85 | sfl.hide(); 86 | var sfe = $("#sketch-files-item > div.toggle-menu"); 87 | 88 | sfe.click(function(){ 89 | $(this).toggleClass("expand"); 90 | sfl.slideToggle("slow"); 91 | 92 | }); 93 | 94 | //Supported Hardware navigation 95 | var shi = $("li#supported-hardware-item"); 96 | var shl = $("ul#supported-hardware-list"); 97 | 98 | shi.prepend( $("
") ); 99 | shl.hide(); 100 | var she = $("#supported-hardware-item > div.toggle-menu"); 101 | 102 | she.click(function(){ 103 | $(this).toggleClass("expand"); 104 | shl.slideToggle("slow"); 105 | 106 | }); 107 | 108 | //APIs navigation 109 | var api = $("li#bring-your-own-thing-api-item"); 110 | var apl = $("ul#bring-your-own-thing-api-list"); 111 | 112 | api.prepend( $("
") ); 113 | apl.hide(); 114 | var ape = $("#bring-your-own-thing-api-item > div.toggle-menu"); 115 | 116 | ape.click(function(){ 117 | $(this).toggleClass("expand"); 118 | apl.slideToggle("slow"); 119 | 120 | }); 121 | 122 | //Security navigation 123 | var sci = $("li#security-item"); 124 | var scl = $("ul#security-list"); 125 | 126 | sci.prepend( $("
") ); 127 | scl.hide(); 128 | var sce = $("#security-item > div.toggle-menu"); 129 | 130 | sce.click(function(){ 131 | $(this).toggleClass("expand"); 132 | scl.slideToggle("slow"); 133 | 134 | }); 135 | 136 | //LoRa navigation 137 | var loraItem = $("li#lora-item"); 138 | var loraList = $("ul#lora-list"); 139 | 140 | loraItem.prepend( $("
") ); 141 | loraList.hide(); 142 | var loraE = $("#lora-item > div.toggle-menu"); 143 | 144 | loraE.click(function(){ 145 | $(this).toggleClass("expand"); 146 | loraList.slideToggle("slow"); 147 | 148 | }); 149 | 150 | //MQTT API navigation 151 | var mqttItem = $("li#bring-your-own-thing-api-item"); 152 | var mqttList = $("ul#bring-your-own-thing-api-list"); 153 | 154 | mqttItem.prepend( $("
") ); 155 | mqttList.hide(); 156 | var mqttE = $("bring-your-own-thing-api-item > div.toggle-menu"); 157 | 158 | mqttE.click(function(){ 159 | $(this).toggleClass("expand"); 160 | mqttList.slideToggle("slow"); 161 | 162 | }); 163 | 164 | //IoT Ready navigation 165 | var iotReadyItem = $("li#iot-ready-program-item"); 166 | var iotReadyList = $("ul#iot-ready-program-list"); 167 | 168 | iotReadyItem.prepend( $("
") ); 169 | iotReadyList.hide(); 170 | var iotE = $("#iot-ready-program-item > div.toggle-menu"); 171 | 172 | iotE.click(function(){ 173 | $(this).toggleClass("expand"); 174 | iotReadyList.slideToggle("slow"); 175 | 176 | }); 177 | 178 | //Cayenne API navigation 179 | var cayenneApiItem = $("li#cayenne-api-item"); 180 | var cayenneApiList = $("ul#cayenne-api-list"); 181 | 182 | cayenneApiItem.prepend( $("
") ); 183 | cayenneApiList.hide(); 184 | var cayenneApiE = $("#cayenne-api-item > div.toggle-menu"); 185 | 186 | cayenneApiE.click(function(){ 187 | $(this).toggleClass("expand"); 188 | cayenneApiList.slideToggle("slow"); 189 | 190 | }); 191 | 192 | // $window.resize(function () { 193 | // var viewportWidth = $window.width(); 194 | // if (viewportWidth < 1) { 195 | // $("img").css('height', 'auto'); 196 | // } 197 | // }); 198 | 199 | 200 | 201 | }); 202 | 203 | 204 | 205 | $document.scroll(function(){ 206 | if( $("a#downloads-link").hasClass("active") ){ 207 | if( $("ul#downloads-list:hidden") ){ 208 | $("ul#downloads-list").css("display", "block"); 209 | $("#downloads-item > div.toggle-menu").addClass("expand"); 210 | $("ul#introduction-list").css("display", "none"); 211 | $("#introduction-item > div.toggle-menu").removeClass("expand"); 212 | } 213 | } 214 | else if( $("a#introduction-link").hasClass("active") ){ 215 | if( $("ul#introduction-list:hidden") ){ 216 | $("ul#introduction-list").css("display", "block"); 217 | $("#introduction-item > div.toggle-menu").addClass("expand"); 218 | } 219 | } 220 | else if( $("a#getting-started-link").hasClass("active") ){ 221 | if( $("ul#getting-started-list:hidden") ){ 222 | $("ul#getting-started-list").css("display", "block"); 223 | $("#getting-started-item > div.toggle-menu").addClass("expand"); 224 | $("ul#downloads-list").css("display", "none"); 225 | $("#downloads-item > div.toggle-menu").removeClass("expand"); 226 | } 227 | } 228 | else if( $("a#features-link").hasClass("active") ){ 229 | if( $("ul#features-list:hidden") ){ 230 | $("ul#features-list").css("display", "block"); 231 | $("#features-item > div.toggle-menu").addClass("expand"); 232 | $("ul#getting-started-list").css("display", "none"); 233 | $("#getting-started-item > div.toggle-menu").removeClass("expand"); 234 | } 235 | } 236 | else if( $("a#custom-widgets-link").hasClass("active") ){ 237 | if( $("ul#custom-widgets-list:hidden") ){ 238 | $("ul#custom-widgets-list").css("display", "block"); 239 | $("#custom-widgets-item > div.toggle-menu").addClass("expand"); 240 | $("ul#features-list").css("display", "none"); 241 | $("#features-item > div.toggle-menu").removeClass("expand"); 242 | } 243 | } 244 | else if( $("a#sketch-files-link").hasClass("active") ){ 245 | if( $("ul#sketch-files-list:hidden") ){ 246 | $("ul#sketch-files-list").css("display", "block"); 247 | $("#sketch-files-item > div.toggle-menu").addClass("expand"); 248 | $("ul#custom-widgets-list").css("display", "none"); 249 | $("#custom-widgets-item > div.toggle-menu").removeClass("expand"); 250 | } 251 | } 252 | else if( $("a#lora-link").hasClass("active") ){ 253 | if( $("ul#lora-list:hidden") ){ 254 | $("ul#lora-list").css("display", "block"); 255 | $("#lora-item > div.toggle-menu").addClass("expand"); 256 | $("ul#sketch-files-list").css("display", "none"); 257 | $("#sketch-files-item > div.toggle-menu").removeClass("expand"); 258 | } 259 | } 260 | else if( $("a#supported-hardware-link").hasClass("active") ){ 261 | if( $("ul#supported-hardware-list:hidden") ){ 262 | $("ul#supported-hardware-list").css("display", "block"); 263 | $("#supported-hardware-item > div.toggle-menu").addClass("expand"); 264 | $("ul#sketch-files-list").css("display", "none"); 265 | $("#sketch-files-item > div.toggle-menu").removeClass("expand"); 266 | } 267 | } 268 | else if( $("a#mqtt-api-link").hasClass("active") ){ 269 | if( $("ul#mqtt-api-list:hidden") ){ 270 | $("ul#mqtt-api-list").css("display", "block"); 271 | $("#mqtt-api-item > div.toggle-menu").addClass("expand"); 272 | $("ul#supported-hardware-list").css("display", "none"); 273 | $("#supported-hardware-item > div.toggle-menu").removeClass("expand"); 274 | } 275 | } 276 | else if( $("a#security-link").hasClass("active") ){ 277 | if( $("ul#security-list:hidden") ){ 278 | $("ul#security-list").css("display", "block"); 279 | $("#security-item > div.toggle-menu").addClass("expand"); 280 | $("ul#apis-list").css("display", "none"); 281 | $("#apis-item > div.toggle-menu").removeClass("expand"); 282 | } 283 | } 284 | else if( $("a#cayenne-api-link").hasClass("active") ){ 285 | if( $("ul#cayenne-api-list:hidden") ){ 286 | $("ul#cayenne-api-list").css("display", "block"); 287 | $("#cayenne-api-item > div.toggle-menu").addClass("expand"); 288 | $("ul#cayenne-api-list").css("display", "none"); 289 | $("#cayenne-api-item > div.toggle-menu").removeClass("expand"); 290 | } 291 | } 292 | }) 293 | 294 | })(jQuery); 295 | 296 | -------------------------------------------------------------------------------- /bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "flatdoc", 3 | "main": [ 4 | "flatdoc.js", 5 | "legacy.js", 6 | "theme-white/script.js", 7 | "theme-white/style.css" 8 | ], 9 | "homepage": "https://github.com/rstacruz/flatdoc", 10 | "authors": [ 11 | "Rico Sta. Cruz " 12 | ], 13 | "description": "Fetch Markdown files and render them as full pages.", 14 | "moduleType": [ 15 | "globals" 16 | ], 17 | "keywords": [ 18 | "documentation", 19 | "markdown" 20 | ], 21 | "license": "MIT", 22 | "ignore": [ 23 | "**/.*", 24 | "node_modules", 25 | "bower_components", 26 | "test", 27 | "tests" 28 | ] 29 | } 30 | -------------------------------------------------------------------------------- /bower_components/jquery-scrollspy/.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "airbnb/legacy", 3 | "rules": { 4 | // Override Airbnb's style guide defaults for ES5 5 | "camelcase": [2, {"properties": "always"}], 6 | "indent": [2, 4, {"SwitchCase": 1}], 7 | "max-len": [2, 256, 4], 8 | "no-param-reassign": 0, 9 | "no-shadow": 0, 10 | "no-use-before-define": 0, 11 | // "padded-blocks": 0, 12 | // "spaced-comment": 0, 13 | "vars-on-top": 0 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /bower_components/jquery-scrollspy/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | -------------------------------------------------------------------------------- /bower_components/jquery-scrollspy/README.md: -------------------------------------------------------------------------------- 1 | # NOTE: This is the latest version of ScrollSpy, which includes a ton of bug fixes and efficiency improvements. It's recommended that you use this version for now instead of the official (which hasn't been updated in a while). 2 | 3 | # jQuery-ScrollSpy 4 | 5 | An adaptation of the Mootools Scrollspy (http://davidwalsh.name/mootools-scrollspy) plugin for jQuery 6 | 7 | (c) 2011 Samuel Alexander (https://github.com/sxalexander/jquery-scrollspy) 8 | 9 | (c) 2015 SoftwareSpot 10 | 11 | Released under The MIT License. 12 | 13 | ## Description: 14 | 15 | ScrollSpy is a simple jQuery plugin for firing events based on where the user has scrolled to in a page. 16 | 17 | ## Homepage: 18 | 19 | https://github.com/softwarespot/jquery-scrollspy 20 | 21 | ## Source: 22 | 23 | Hosted at GitHub; browse at: 24 | 25 | https://github.com/softwarespot/jquery-scrollspy/tree/master 26 | 27 | Or clone from: 28 | 29 | git://github.com/softwarespot/jquery-scrollspy.git 30 | 31 | ## Usage: 32 | 33 | 1. Insert the necessary elements in to your document's `` section, e.g.: 34 | 35 | ```html 36 | 37 | 38 | ``` 39 | 40 | 2. Initialise ScrollSpy once the DOM has been loaded: 41 | 42 | ```javascript 43 | 60 | ``` 61 | 62 | Check out the /examples for more info ! 63 | 64 | ## Documentation: 65 | 66 | ScrollSpy function signature: 67 | ```javascript 68 | $('container').scrollspy(options, action) 69 | ``` 70 | 71 | Default options for ScrollSpy: 72 | ```javascript 73 | // default options for ScrollSpy 74 | var defaults = { 75 | // the offset to be applied to the left and top positions of the container 76 | buffer: 0, 77 | 78 | // the element to apply the 'scrolling' event to (default window) 79 | container: window, 80 | 81 | // the maximum value of the X or Y coordinate, depending on mode the selected 82 | max: 0, 83 | 84 | // the maximum value of the X or Y coordinate, depending on mode the selected 85 | min: 0, 86 | 87 | // whether to listen to the X (horizontal) or Y (vertical) scrolling 88 | mode: 'vertical', 89 | 90 | // namespace to append to the 'scroll' event 91 | namespace: 'scrollspy', 92 | 93 | // call the following callback function every time the user enters the min / max zone 94 | onEnter: null, 95 | 96 | // call the following callback function every time the user leaves the min / max zone 97 | onLeave: null, 98 | 99 | // call the following callback function every time the user leaves the top zone 100 | onLeaveTop: null, 101 | 102 | // call the following callback function every time the user leaves the bottom zone 103 | onLeaveBottom: null, 104 | 105 | // call the following callback function on each scroll event within the min and max parameters 106 | onTick: null, 107 | 108 | // call the following callback function on each scroll event when the element is inside the viewable view port 109 | onView: null 110 | }; 111 | ``` 112 | 113 | Events are triggered by ScrollSpy are: 114 | 115 | scrollTick: Fires on each scroll event within the min and max parameters: 116 | position: an object with the current X and Y position. 117 | inside: a Boolean value for whether or not the user is within the min and max parameters 118 | enters: the number of times the min / max has been entered. 119 | leaves: the number of times the min / max has been left. 120 | 121 | scrollEnter: Fires every time the user enters the min / max zone: 122 | position: an object with the current X and Y position. 123 | enters: the number of times the min / max has been entered. 124 | 125 | scrollLeave: Fires every time the user leaves the min / max zone: 126 | position: an object with the current X and Y position. 127 | leaves: the number of times the min / max has been left. 128 | 129 | scrollLeaveTop: Fires every time the user leaves the top zone: 130 | position: an object with the current X and Y position. 131 | leaves: the number of times the min / max has been left. 132 | 133 | scrollLeaveBottom: Fires every time the user leaves the bottom zone: 134 | position: an object with the current X and Y position. 135 | leaves: the number of times the min / max has been left. 136 | 137 | scrollView: Fires every time the element is inside the viewable view port: 138 | position: an object with the current X and Y position. 139 | leaves: the number of times the min / max has been left. 140 | 141 | ### Tidy up 142 | 143 | To destroy ScrollSpy for a particular container, simple pass 'destroy' as the action parameter. The only options that will be honoured are `container` and `namespace`. 144 | 145 | ## A note about forking: 146 | 147 | By forking this project you hereby grant permission for any commits to your fork to be 148 | merged back into this repository and, with attribution, be released under the terms of 149 | the MIT License. 150 | 151 | ## Contribute 152 | 153 | To contribute to the project, you will first need to install [node](https://nodejs.org) globally on your system. Once installation has completed, change the working directory to the plugin's location and run the following command: 154 | 155 | ```shell 156 | npm install 157 | ``` 158 | 159 | After installation of the local modules, you're ready to start contributing to the project. Before you submit your PR, please don't forget to call `gulp`, which will run against [JSHint](http://jshint.com) for any errors, but will also minify the plugin. 160 | 161 | ##### Watch 162 | Call the following command to start 'watching' for any changes to the main JavaScript file(s). This will automatically invoke JSHint and Uglify. 163 | ```shell 164 | gulp watch 165 | ``` 166 | 167 | ##### JSHint 168 | Call the following command to invoke JSHint and check that the changes meet the requirements set in .jshintrc. 169 | ```shell 170 | gulp jshint 171 | ``` 172 | 173 | ##### Uglify 174 | Call the following command to invoke Uglify, which will minify the main JavaScript file(s) and output to a .min.js file respectively. 175 | ```shell 176 | gulp uglify 177 | ``` 178 | 179 | ##### Build 180 | Call the following command to invoke both JSHint and Uglify. 181 | ```shell 182 | gulp 183 | ``` 184 | -------------------------------------------------------------------------------- /bower_components/jquery-scrollspy/bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "jquery-scrollspy", 3 | "homepage": "https://github.com/sxalexander/jquery-scrollspy/", 4 | "description": "scrollspy is a simple jQuery plugin for firing events based on where the user has scrolled to in a page.", 5 | "main": "jquery-scrollspy.min.js", 6 | "keywords": [ 7 | "scrolling", 8 | "scroll" 9 | ], 10 | "license": "MIT", 11 | "ignore": [ 12 | ], 13 | "dependencies": { 14 | "jquery": ">=1.7.0" 15 | }, 16 | "devDependencies": { 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /bower_components/jquery-scrollspy/examples/colors.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | jQuery Scrollspy demo 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 37 | 38 | 39 |
40 |
41 |
42 |

Scroll down to see the background color change

43 |
44 |

The White Team

45 |
46 |
47 |

The Red Team

48 |
49 |
50 |

The Blue Team

51 |
52 |
53 |

The Green Team

54 |
55 |
56 |

The Black Team

57 |
58 |
59 |
60 |
61 |
62 |
63 | 64 | 65 | 66 | 67 | 93 | 94 | 95 | -------------------------------------------------------------------------------- /bower_components/jquery-scrollspy/examples/fixednav.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | JQuery Scrollspy demo 6 | 7 | 8 | 9 | 68 | 69 | 70 |
71 |
72 | 75 | 93 |
94 |
95 |

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nihil opus est exemplis hoc facere longius. In his igitur partibus duabus nihil erat, quod Zeno commutare gestiret. Duo Reges: constructio interrete. Quid nunc honeste dicit? Age, inquies, ista parva sunt. Si id dicis, vicimus.

96 |

Primum quid tu dicis breve? Nam ista vestra: Si gravis, brevis; Tollenda est atque extrahenda radicitus. Recte dicis; Est enim effectrix multarum et magnarum voluptatum. Vide ne ista sint Manliana vestra aut maiora etiam, si imperes quod facere non possim. Qua tu etiam inprudens utebare non numquam. Atque haec ita iustitiae propria sunt, ut sint virtutum reliquarum communia.

97 |
 98 |                 Nam neque virtute retinetur ille in vita, nec iis, qui sine
 99 |                 virtute sunt, mors est oppetenda.
100 | 
101 |                 Quid enim ab antiquis ex eo genere, quod ad disserendum
102 |                 valet, praetermissum est?
103 |                         
104 |

Immo videri fortasse. Minime vero istorum quidem, inquit. Pugnant Stoici cum Peripateticis. Sed quot homines, tot sententiae;

105 |

Haeret in salebra. Estne, quaeso, inquam, sitienti in bibendo voluptas? Octavio fuit, cum illam severitatem in eo filio adhibuit, quem in adoptionem D. 106 | Scrupulum, inquam, abeunti; De malis autem et bonis ab iis animalibus, quae nondum depravata sint, ait optime iudicari. Cum id fugiunt, re eadem defendunt, quae Peripatetici, verba. 107 |

108 |

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nihil opus est exemplis hoc facere longius. In his igitur partibus duabus nihil erat, quod Zeno commutare gestiret. Duo Reges: constructio interrete. Quid nunc honeste dicit? Age, inquies, ista parva sunt. Si id dicis, vicimus.

109 |

Primum quid tu dicis breve? Nam ista vestra: Si gravis, brevis; Tollenda est atque extrahenda radicitus. Recte dicis; Est enim effectrix multarum et magnarum voluptatum. Vide ne ista sint Manliana vestra aut maiora etiam, si imperes quod facere non possim. Qua tu etiam inprudens utebare non numquam. Atque haec ita iustitiae propria sunt, ut sint virtutum reliquarum communia.

110 |
111 |                 Nam neque virtute retinetur ille in vita, nec iis, qui sine
112 |                 virtute sunt, mors est oppetenda.
113 | 
114 |                 Quid enim ab antiquis ex eo genere, quod ad disserendum
115 |                 valet, praetermissum est?
116 |               
117 |

Immo videri fortasse. Minime vero istorum quidem, inquit. Pugnant Stoici cum Peripateticis. Sed quot homines, tot sententiae;

118 |

Haeret in salebra. Estne, quaeso, inquam, sitienti in bibendo voluptas? Octavio fuit, cum illam severitatem in eo filio adhibuit, quem in adoptionem D. 119 | Scrupulum, inquam, abeunti; De malis autem et bonis ab iis animalibus, quae nondum depravata sint, ait optime iudicari. Cum id fugiunt, re eadem defendunt, quae Peripatetici, verba. 120 |

121 |

Tu enim ista lenius, hic Stoicorum more nos vexat.

122 |

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Dicet pro me ipsa virtus nec dubitabit isti vestro beato M. Sed residamus, inquit, si placet. Si quae forte-possumus. Quid censes in Latino fore? Duo Reges: constructio interrete. Nummus in Croesi divitiis obscuratur, pars est tamen divitiarum. An tu me de L. Quae contraria sunt his, malane? An potest, inquit ille, quicquam esse suavius quam nihil dolere? Itaque in rebus minime obscuris non multus est apud eos disserendi labor.

123 |
124 | Omne enim animal, simul et ortum est, se ipsum et omnes partes suas diligit duasque, quae maximae sunt, in primis amplectitur, animum et corpus, deinde utriusque partes. 125 |
126 |

Bonum incolumis acies: misera caecitas. Ego vero volo in virtute vim esse quam maximam; Traditur, inquit, ab Epicuro ratio neglegendi doloris. Quid de Platone aut de Democrito loquar? Inde igitur, inquit, ordiendum est. Philosophi autem in suis lectulis plerumque moriuntur. Quantum Aristoxeni ingenium consumptum videmus in musicis? Qui enim voluptatem ipsam contemnunt, iis licet dicere se acupenserem maenae non anteponere.

127 |
    128 |
  • Sed quia studebat laudi et dignitati, multum in virtute processerat.
  • 129 |
  • Quae similitudo in genere etiam humano apparet.
  • 130 |
  • Beatus sibi videtur esse moriens.
  • 131 |
  • Odium autem et invidiam facile vitabis.
  • 132 |
  • Commoda autem et incommoda in eo genere sunt, quae praeposita et reiecta diximus;
  • 133 |
134 |

Quorum altera prosunt, nocent altera. At, si voluptas esset bonum, desideraret. Haec para/doca illi, nos admirabilia dicamus. Et quidem iure fortasse, sed tamen non gravissimum est testimonium multitudinis. Illa argumenta propria videamus, cur omnia sint paria peccata. Hanc ergo intuens debet institutum illud quasi signum absolvere.

135 |
136 |
137 |
138 |
139 | 140 | 141 | 142 | 159 | 160 | 161 | -------------------------------------------------------------------------------- /bower_components/jquery-scrollspy/gulpfile.js: -------------------------------------------------------------------------------- 1 | /* global require */ 2 | 3 | var gulp = require('gulp'); 4 | var eslint = require('gulp-eslint'); 5 | var gulpIf = require('gulp-if'); 6 | var rename = require('gulp-rename'); 7 | var uglify = require('gulp-uglify'); 8 | 9 | // Assets for the project 10 | var Assets = { 11 | main: './jquery-scrollspy.js', 12 | minified: './jquery-scrollspy.min.js', 13 | package: './package.json', 14 | readme: './README.md', 15 | source: './', 16 | }; 17 | 18 | // See the uglify documentation for more details 19 | var _uglifySettings = { 20 | compress: { 21 | comparisons: true, 22 | conditionals: true, 23 | /* jscs: disable */ 24 | dead_code: true, 25 | drop_console: true, 26 | /* jscs: enable */ 27 | unsafe: true, 28 | unused: true, 29 | }, 30 | }; 31 | 32 | // Check the main js file(s) meets the following standards outlined in .eslintrc 33 | gulp.task('eslint', function esLintTask() { 34 | // Has ESLint fixed the file contents? 35 | function isFixed(file) { 36 | return file.eslint !== undefined && file.eslint !== null && file.eslint.fixed; 37 | } 38 | 39 | return gulp.src(Assets.main) 40 | .pipe(eslint({ 41 | fix: true, 42 | useEslintrc: '.eslintrc', 43 | })) 44 | .pipe(eslint.format()) 45 | .pipe(gulpIf(isFixed, gulp.dest(Assets.source))); 46 | }); 47 | 48 | // Uglify aka minify the main file 49 | gulp.task('uglify', function uglifyTask() { 50 | return gulp.src(Assets.main) 51 | .pipe(uglify(_uglifySettings)) 52 | .pipe(rename(Assets.minified)) 53 | .pipe(gulp.dest(Assets.source)); 54 | }); 55 | 56 | // Watch for changes to the main file 57 | gulp.task('watch', function watchTask() { 58 | gulp.watch(Assets.main, ['eslint', 'uglify']); 59 | }); 60 | 61 | // Register the default task 62 | gulp.task('default', ['eslint', 'uglify']); 63 | 64 | // 'gulp eslint' to check the syntax of the main js file(s) 65 | // 'gulp uglify' to uglify the main file 66 | -------------------------------------------------------------------------------- /bower_components/jquery-scrollspy/jquery-scrollspy.js: -------------------------------------------------------------------------------- 1 | /* 2 | * jQuery ScrollSpy Plugin 3 | * Author: @sxalexander, softwarespot 4 | * Licensed under the MIT license 5 | */ 6 | (function jQueryScrollspy(window, $) { 7 | // Plugin Logic 8 | 9 | $.fn.extend({ 10 | scrollspy: function scrollspy(options, action) { 11 | // If the options parameter is a string, then assume it's an 'action', therefore swap the parameters around 12 | if (_isString(options)) { 13 | var tempOptions = action; 14 | 15 | // Set the action as the option parameter 16 | action = options; 17 | 18 | // Set to be the reference action pointed to 19 | options = tempOptions; 20 | } 21 | 22 | // override the default options with those passed to the plugin 23 | options = $.extend({}, _defaults, options); 24 | 25 | // sanitize the following option with the default value if the predicate fails 26 | _sanitizeOption(options, _defaults, 'container', _isObject); 27 | 28 | // cache the jQuery object 29 | var $container = $(options.container); 30 | 31 | // check if it's a valid jQuery selector 32 | if ($container.length === 0) { 33 | return this; 34 | } 35 | 36 | // sanitize the following option with the default value if the predicate fails 37 | _sanitizeOption(options, _defaults, 'namespace', _isString); 38 | 39 | // check if the action is set to DESTROY/destroy 40 | if (_isString(action) && action.toUpperCase() === 'DESTROY') { 41 | $container.off('scroll.' + options.namespace); 42 | return this; 43 | } 44 | 45 | // sanitize the following options with the default values if the predicates fails 46 | _sanitizeOption(options, _defaults, 'buffer', $.isNumeric); 47 | _sanitizeOption(options, _defaults, 'max', $.isNumeric); 48 | _sanitizeOption(options, _defaults, 'min', $.isNumeric); 49 | 50 | // callbacks 51 | _sanitizeOption(options, _defaults, 'onEnter', $.isFunction); 52 | _sanitizeOption(options, _defaults, 'onLeave', $.isFunction); 53 | _sanitizeOption(options, _defaults, 'onLeaveTop', $.isFunction); 54 | _sanitizeOption(options, _defaults, 'onLeaveBottom', $.isFunction); 55 | _sanitizeOption(options, _defaults, 'onTick', $.isFunction); 56 | 57 | if ($.isFunction(options.max)) { 58 | options.max = options.max(); 59 | } 60 | 61 | if ($.isFunction(options.min)) { 62 | options.min = options.min(); 63 | } 64 | 65 | // check if the mode is set to VERTICAL/vertical 66 | var isVertical = window.String(options.mode).toUpperCase() === 'VERTICAL'; 67 | 68 | return this.each(function each() { 69 | // cache this 70 | var _this = this; 71 | 72 | // cache the jQuery object 73 | var $element = $(_this); 74 | 75 | // count the number of times a container is entered 76 | var enters = 0; 77 | 78 | // determine if the scroll is with inside the container 79 | var inside = false; 80 | 81 | // count the number of times a container is left 82 | var leaves = 0; 83 | 84 | // create a scroll listener for the container 85 | $container.on('scroll.' + options.namespace, function onScroll() { 86 | // cache the jQuery object 87 | var $this = $(this); 88 | 89 | // create a position object literal 90 | var position = { 91 | top: $this.scrollTop(), 92 | left: $this.scrollLeft(), 93 | }; 94 | 95 | var containerHeight = $container.height(); 96 | 97 | var max = options.max; 98 | 99 | var min = options.min; 100 | 101 | var xAndY = isVertical ? position.top + options.buffer : position.left + options.buffer; 102 | 103 | if (max === 0) { 104 | // get the maximum value based on either the height or the outer width 105 | max = isVertical ? containerHeight : $container.outerWidth() + $element.outerWidth(); 106 | } 107 | 108 | // if we have reached the minimum bound, though are below the max 109 | if (xAndY >= min && xAndY <= max) { 110 | // trigger the 'scrollEnter' event 111 | if (!inside) { 112 | inside = true; 113 | enters++; 114 | 115 | // trigger the 'scrollEnter' event 116 | $element.trigger('scrollEnter', { 117 | position: position, 118 | }); 119 | 120 | // call the 'onEnter' function 121 | if (options.onEnter !== null) { 122 | options.onEnter(_this, position); 123 | } 124 | } 125 | 126 | // trigger the 'scrollTick' event 127 | $element.trigger('scrollTick', { 128 | position: position, 129 | inside: inside, 130 | enters: enters, 131 | leaves: leaves, 132 | }); 133 | 134 | // call the 'onTick' function 135 | if (options.onTick !== null) { 136 | options.onTick(_this, position, inside, enters, leaves); 137 | } 138 | } else { 139 | if (inside) { 140 | inside = false; 141 | leaves++; 142 | 143 | // trigger the 'scrollLeave' event 144 | $element.trigger('scrollLeave', { 145 | position: position, 146 | leaves: leaves, 147 | }); 148 | 149 | // call the 'onLeave' function 150 | if (options.onLeave !== null) { 151 | options.onLeave(_this, position); 152 | } 153 | 154 | if (xAndY <= min) { 155 | // trigger the 'scrollLeaveTop' event 156 | $element.trigger('scrollLeaveTop', { 157 | position: position, 158 | leaves: leaves, 159 | }); 160 | 161 | // call the 'onLeaveTop' function 162 | if (options.onLeaveTop !== null) { 163 | options.onLeaveTop(_this, position); 164 | } 165 | } else if (xAndY >= max) { 166 | // trigger the 'scrollLeaveBottom' event 167 | $element.trigger('scrollLeaveBottom', { 168 | position: position, 169 | leaves: leaves, 170 | }); 171 | 172 | // call the 'onLeaveBottom' function 173 | if (options.onLeaveBottom !== null) { 174 | options.onLeaveBottom(_this, position); 175 | } 176 | } 177 | } else { 178 | // Idea taken from: http://stackoverflow.com/questions/5353934/check-if-element-is-visible-on-screen 179 | var containerScrollTop = $container.scrollTop(); 180 | 181 | // Get the element height 182 | var elementHeight = $element.height(); 183 | 184 | // Get the element offset 185 | var elementOffsetTop = $element.offset().top; 186 | 187 | if ((elementOffsetTop < (containerHeight + containerScrollTop)) && (elementOffsetTop > (containerScrollTop - elementHeight))) { 188 | // trigger the 'scrollView' event 189 | $element.trigger('scrollView', { 190 | position: position, 191 | }); 192 | 193 | // call the 'onView' function 194 | if (options.onView !== null) { 195 | options.onView(_this, position); 196 | } 197 | } 198 | } 199 | } 200 | }); 201 | }); 202 | }, 203 | }); 204 | 205 | // Fields (Private) 206 | 207 | // Defaults 208 | 209 | // default options 210 | var _defaults = { 211 | // the offset to be applied to the left and top positions of the container 212 | buffer: 0, 213 | 214 | // the element to apply the 'scrolling' event to (default window) 215 | container: window, 216 | 217 | // the maximum value of the X or Y coordinate, depending on mode the selected 218 | max: 0, 219 | 220 | // the maximum value of the X or Y coordinate, depending on mode the selected 221 | min: 0, 222 | 223 | // whether to listen to the X (horizontal) or Y (vertical) scrolling 224 | mode: 'vertical', 225 | 226 | // namespace to append to the 'scroll' event 227 | namespace: 'scrollspy', 228 | 229 | // call the following callback function every time the user enters the min / max zone 230 | onEnter: null, 231 | 232 | // call the following callback function every time the user leaves the min / max zone 233 | onLeave: null, 234 | 235 | // call the following callback function every time the user leaves the top zone 236 | onLeaveTop: null, 237 | 238 | // call the following callback function every time the user leaves the bottom zone 239 | onLeaveBottom: null, 240 | 241 | // call the following callback function on each scroll event within the min and max parameters 242 | onTick: null, 243 | 244 | // call the following callback function on each scroll event when the element is inside the viewable view port 245 | onView: null, 246 | }; 247 | 248 | // Methods (Private) 249 | 250 | // check if a value is an object datatype 251 | function _isObject(value) { 252 | return $.type(value) === 'object'; 253 | } 254 | 255 | // check if a value is a string datatype with a length greater than zero when whitespace is stripped 256 | function _isString(value) { 257 | return $.type(value) === 'string' && $.trim(value).length > 0; 258 | } 259 | 260 | // check if an option is correctly formatted using a predicate; otherwise, return the default value 261 | function _sanitizeOption(options, defaults, property, predicate) { 262 | // set the property to the default value if the predicate returned false 263 | if (!predicate(options[property])) { 264 | options[property] = defaults[property]; 265 | } 266 | } 267 | }(window, window.jQuery)); 268 | -------------------------------------------------------------------------------- /bower_components/jquery-scrollspy/jquery-scrollspy.min.js: -------------------------------------------------------------------------------- 1 | !function(e,n){function o(e){return"object"===n.type(e)}function i(e){return"string"===n.type(e)&&n.trim(e).length>0}function t(e,n,o,i){i(e[o])||(e[o]=n[o])}n.fn.extend({scrollspy:function(l,s){if(i(l)){var a=s;s=l,l=a}l=n.extend({},r,l),t(l,r,"container",o);var c=n(l.container);if(0===c.length)return this;if(t(l,r,"namespace",i),i(s)&&"DESTROY"===s.toUpperCase())return c.off("scroll."+l.namespace),this;t(l,r,"buffer",n.isNumeric),t(l,r,"max",n.isNumeric),t(l,r,"min",n.isNumeric),t(l,r,"onEnter",n.isFunction),t(l,r,"onLeave",n.isFunction),t(l,r,"onLeaveTop",n.isFunction),t(l,r,"onLeaveBottom",n.isFunction),t(l,r,"onTick",n.isFunction),n.isFunction(l.max)&&(l.max=l.max()),n.isFunction(l.min)&&(l.min=l.min());var u="VERTICAL"===e.String(l.mode).toUpperCase();return this.each(function(){var e=this,o=n(e),i=0,t=!1,r=0;c.on("scroll."+l.namespace,function(){var s=n(this),a={top:s.scrollTop(),left:s.scrollLeft()},f=c.height(),p=l.max,m=l.min,v=u?a.top+l.buffer:a.left+l.buffer;if(0===p&&(p=u?f:c.outerWidth()+o.outerWidth()),v>=m&&p>=v)t||(t=!0,i++,o.trigger("scrollEnter",{position:a}),null!==l.onEnter&&l.onEnter(e,a)),o.trigger("scrollTick",{position:a,inside:t,enters:i,leaves:r}),null!==l.onTick&&l.onTick(e,a,t,i,r);else if(t)t=!1,r++,o.trigger("scrollLeave",{position:a,leaves:r}),null!==l.onLeave&&l.onLeave(e,a),m>=v?(o.trigger("scrollLeaveTop",{position:a,leaves:r}),null!==l.onLeaveTop&&l.onLeaveTop(e,a)):v>=p&&(o.trigger("scrollLeaveBottom",{position:a,leaves:r}),null!==l.onLeaveBottom&&l.onLeaveBottom(e,a));else{var g=c.scrollTop(),L=o.height(),h=o.offset().top;f+g>h&&h>g-L&&(o.trigger("scrollView",{position:a}),null!==l.onView&&l.onView(e,a))}})})}});var r={buffer:0,container:e,max:0,min:0,mode:"vertical",namespace:"scrollspy",onEnter:null,onLeave:null,onLeaveTop:null,onLeaveBottom:null,onTick:null,onView:null}}(window,window.jQuery); -------------------------------------------------------------------------------- /bower_components/jquery-scrollspy/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "jquery-scrollspy", 3 | "version": "1.0.0", 4 | "license": "MIT", 5 | "repository": { 6 | "type": "git", 7 | "url": "https://github.com/softwarespot/jquery-scrollspy.git" 8 | }, 9 | "devDependencies": { 10 | "del": "^2.1.0", 11 | "eslint": "^2.5.1", 12 | "eslint-config-airbnb": "^6.2.0", 13 | "gulp": "^3.9.1", 14 | "gulp-eslint": "^2.0.0", 15 | "gulp-if": "^2.0.0", 16 | "gulp-rename": "~1.2.2", 17 | "gulp-replace": "^0.5.4", 18 | "gulp-uglify": "^1.5.3", 19 | "merge2": "^1.0.1" 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /bower_components/jquery-scrollspy/test/demo.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
9 | 10 | 11 | 31 | 32 | -------------------------------------------------------------------------------- /bower_components/jquery-scrollspy/test/memory-leak.coffee: -------------------------------------------------------------------------------- 1 | drool = require('drool') 2 | assert = require('assert') 3 | path = require('path') 4 | 5 | driver = drool.start 6 | chromeOptions: 'no-sandbox' 7 | 8 | webdriver = drool.webdriver 9 | 10 | drool.flow({ 11 | repeatCount: 5 12 | setup: -> 13 | driver.get('file://' + path.join(__dirname, '/demo.html')) 14 | action: -> 15 | driver.findElement(webdriver.By.css('#add')).click() 16 | driver.findElement(webdriver.By.css('#remove')).click() 17 | assert: (after, initial) -> 18 | assert.equal(initial.nodes, after.nodes, 'node count should match') 19 | 20 | }, driver) 21 | 22 | driver.quit() -------------------------------------------------------------------------------- /bower_components/jquery-scrollspy/test/memory-leak.js: -------------------------------------------------------------------------------- 1 | // Generated by CoffeeScript 1.9.3 2 | var assert, driver, drool, path, webdriver; 3 | 4 | drool = require('drool'); 5 | 6 | assert = require('assert'); 7 | 8 | path = require('path'); 9 | 10 | driver = drool.start({ 11 | chromeOptions: 'no-sandbox' 12 | }); 13 | 14 | webdriver = drool.webdriver; 15 | 16 | drool.flow({ 17 | repeatCount: 5, 18 | setup: function() { 19 | return driver.get('file://' + path.join(__dirname, '/demo.html')); 20 | }, 21 | action: function() { 22 | driver.findElement(webdriver.By.css('#add')).click(); 23 | return driver.findElement(webdriver.By.css('#remove')).click(); 24 | }, 25 | assert: function(after, initial) { 26 | return assert.equal(initial.nodes, after.nodes, 'node count should match'); 27 | } 28 | }, driver); 29 | 30 | driver.quit(); 31 | -------------------------------------------------------------------------------- /docs/AZURE.md: -------------------------------------------------------------------------------- 1 | ## Azure IoT Hub & myDevices 2 | 3 | myDevices digests Azure IoT Hub events with the following documentation. A JSON payload with the following requirements should be used for proper integration. See the [IoT Hub](https://docs.microsoft.com/en-us/azure/iot-hub/) documentations for guidelines on how to connect and send telemetry data. 4 | 5 | Helpful links 6 | - [IoT Hub SDKs](https://docs.microsoft.com/en-us/azure/iot-hub/iot-hub-devguide-sdks) 7 | - [SDK for C](https://docs.microsoft.com/en-us/azure/iot-hub/iot-hub-device-sdk-c-intro) 8 | - [MQTT Support](https://docs.microsoft.com/en-us/azure/iot-hub/iot-hub-mqtt-support) 9 | 10 | 11 | ### myDevices Message Schema 12 | 13 | When sending telemetry messages to IoT Hub, follow the JSON schema below. 14 | 15 | | Attribute | Type | Sample 16 | |-------|---------|----------------------------------| 17 | | eui | String | unique hardware identifier 18 | | format | String | `json` or `hex` 19 | | data | Array | An array list of Cayenen LPP objects see below. 20 | 21 | The `data` attribute must be a JSON array of objects, each element having `channel`, `value`, `type` and `unit` porperties. Refer to the list of our supported data types for the `type` and `unit` properties. 22 | 23 | **Example Message Body** 24 | ```json 25 | { 26 | "eui": "ble-stag-01172021", 27 | "format": "json", 28 | "data": [{ 29 | "channel": 5, 30 | "unit": "p", 31 | "value": 100, 32 | "type": "", 33 | "name": "Battery", 34 | "hardware_id": "000a0032874326321" 35 | }, 36 | { 37 | "channel": 100, 38 | "type": "rssi", 39 | "unit": "dbm", 40 | "value": -64, 41 | "name": "Signal", 42 | "hardware_id": "000a0032874326321" 43 | }, 44 | { 45 | "channel": 5, 46 | "unit": "p", 47 | "value": 82, 48 | "type": "", 49 | "name": "Battery", 50 | "hardware_id": "000a0032874326323" 51 | }, 52 | { 53 | "channel": 100, 54 | "type": "rssi", 55 | "unit": "dbm", 56 | "value": -73, 57 | "name": "Signal", 58 | "hardware_id": "000a0032874326323" 59 | } 60 | ] 61 | } 62 | ``` -------------------------------------------------------------------------------- /docs/CAYENNEAPI.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | # Cayenne Cloud API (Deprecated) 4 | 5 | ## Overview 6 | 7 | The Cayenne Cloud API allows for interacting and creating applications using the myDevices IoT RESTful API. REST is a lightweight, stateless web service standard that myDevices IoT provides to partners and customers. Our REST API is secured with OAuth2 standard, which offers increased security by using JWT access tokens. In addition to Authorization and Authentication mechanism, we encrypt all transport communications with TLS/SSL endpoints. 8 | 9 | ## Preparing to use the API 10 | 11 | ### Create a Cayenne account 12 | 13 | In order to use the Cayenne Cloud API, you will need to first create a Cayenne account. Visit the Cayenne website and create an account. 14 | 15 |


get started for free

16 | 17 |


account sign up

18 | 19 | ### Obtain your Cayenne Cloud API Key 20 | 21 | Before you can use the Cayenne Cloud API you will need to obtain your **App Key** and **App Secret**. In order for your custom application to successfully connect with Cayenne you will need to provide these keys when using the Cayenne Cloud API. 22 | 23 | *TIP: For more information how these keys are used, see the [Authentication section](https://developers.mydevices.com/cayenne/docs/cayenne-api/#cayenne-cloud-api-deprecated-http-api-reference-authentication-users-applications) of the HTTP API documentation.* 24 | 25 | To obtain your keys, log into your account and select **Create App**. The *App Credentials* page that appears contains your keys. Copy & paste the **App Key** and **App Secret** into your code. 26 | 27 |


Create App example

28 | 29 | ## HTTP API Reference 30 | 31 | The myDevices IoT platform is composed of micro services. By not having a monolith application, we can maintain a high level of uptime without taking down the whole platform. When issues arise, the system is still operational and just portions of the platform might not be reachable. Not to mention, the benefits of having micro service also is reflected in the speed and code quality. 32 | 33 | ### Getting Started 34 | 35 | At a glance, we have a sandbox service that provide interactivity with the API to enhance and speed development while building applications. Before using the API users or applications need to authenticate to our authentication service to obtain a token. 36 | 37 | 38 | ### Authentication, Users & Applications 39 | 40 | myDevices IoT API is protected by JWT tokens and established ACL rules. We use the oAuth2 protocol to authenticate users and applications. The authentication service that provide these tokens support all of the oAuth2 authentication grant types: 41 | 42 | - Authorization code grant 43 | - Resource owner grant 44 | - Refresh token grant 45 | - Client credentials grant 46 | 47 | In addition to oAuth2, our authentication service also incorporates Single Sign On for internal and public facing applications, user management, password reset flows, and application management. 48 | 49 | | HTTP Status Code | Reason | 50 | |-------|-------------------------------------------| 51 | | 200 | Operation success | 52 | | 201 | Object added | 53 | | 400 | Bad Request: payload validation | 54 | | 401 | Unauthorized: Invalid or expired token used. | 55 | 56 | All authentication requests are directed to **``https://accounts.mydevices.com``**. 57 | 58 | ##### Get User Information 59 | 60 | Get specific user information 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 |
GET/auth/realms/cayenne/protocol/openid-connect/userinfo
70 | 71 | | Header | Value | 72 | |-------|-------------------------------------------| 73 | | Authorization | Bearer JWT_TOKEN | 74 | 75 | **Response Model** 76 | ``` 77 | { 78 | "sub": "XXXXXXXX", 79 | "email_verified": false, 80 | "email": "some@email.com", 81 | "user_id": "XXXXXXXX", 82 | "given_name": "Name", 83 | "family_name": "LastName", 84 | "name": "Name Lastname" 85 | } 86 | ``` 87 | 88 | Additionally, JWT tokens already contain user information. A JWT token is deviced into 3 parts, all separated by a `.` character. The middle part, is a JSON object base 64 encoded that contains user information among other information like roles and scopes granted. 89 | 90 | #### User Password 91 | 92 | User password can be reset at the following url: **``https://accounts.mydevices.com/auth/realms/cayenne/login-actions/reset-credentials``**. 93 | 94 | ##### Token Exchange Step 95 | 96 | With the user authenticated and the application allowed access, it must now exchange the code grant for an actual usable set of access and refresh tokens for the user. The application should thus make a **server side** request to the following URL: 97 | 98 | ``` 99 | POST https://accounts.mydevices.com/auth/realms/cayenne/protocol/openid-connect/token 100 | { 101 | “grant_type”: “authorization_code”, 102 | “code”: “”, 103 | “redirect_uri”: “”, 104 | “client_id”: “”, 105 | “client_secret”: “” 106 | } 107 | ``` 108 | 109 | **Payload parameters:** 110 | 111 | - grant_type: should be **authorization_code** as this step is exchanging an authorization code for a token 112 | - code: the authorization code received from the previous step 113 | - redirect_uri: should be the same re-direct uri provided in the initial step of the process. 114 | - client_id: the unique id for the 3rd party application 115 | - client_secret: a unique key provided when the 3rd party application was created. This key should only be sent by a server side application and never exposed to the client. 116 | 117 | **Error behaviors:** 118 | 119 | - Incorrect grant_type - Not sending the grant_type of authorization_code 120 | - Incorrect code - Sending an authorization code which has expired or is missing 121 | - Missing or incorrect redirect_uri - The sent redirect uri should match the original redirect uri sent to obtain the authorization code. If it is not sent or different an error will be returned. 122 | - Incorrect client details - If the client_id or client_secret are missing or incorrect an error will be returned. 123 | 124 | **Success behavior:** Successfully exchanging the authorization code for a token will result in an access_token and refresh_token for that user. 125 | 126 | #### Oauth2 Authentication Implicit Flow 127 | 128 | The implicit flow is similar to the explicit flow except it is designed to be utilized by single page, mobile and other applications which cannot provide guarantees of protection for application secrets. Therefore there is no exchange of a code grant for an access and refresh token pair. Simply, if the initial authentication is successful an access token will be provided as a hash fragment to the redirected user. Also note that due to the insecure nature of these applications, a refresh token will not be issued. The following steps describe the flow in more detail: 129 | 130 | ##### Client Redirect to Authentication Server Step 131 | 132 | The user must be authenticated against the authorization server by directing them to the following link: 133 | 134 | ``` 135 | GET https://accounts.mydevices.com/auth/realms/cayenne/protocol/openid-connect/auth?response_type=token&client_id=&redirect_uri=&scope=&state= 136 | ``` 137 | 138 | **Query parameters:** 139 | 140 | - response_type - Should be **token** for this leg of the implicit authentication flow. 141 | - client_id - The identifier of the client application received upon application creation 142 | - redirect_uri - The URI which the client is expected to be returned after successfully authenticating with Cayenne. This redirect uri must have been added to the list of allowable redirects prior to authentication. 143 | - scope - A comma delimited list of grants that the 3rd party application wishes to receive on behalf of the user. 144 | - state - A randomly generated string utilized by the 3rd party application to protect against csrf attacks. 145 | 146 | **Error Behaviors:** 147 | 148 | - Missing or non-whitelisted redirect_uri - The request will be redirected back to the 3rd party application with an error stating an incorrect redirect_uri was presented 149 | - Incorrect client_id - Not passing a client id or sending one that does not match our records will result in redirection back to the 3rd party application with a corresponding error. 150 | - Incorrect response type - Passing a response_type of anything other than code for this leg of the process will result in a redirection back to 3rd party application with an appropriate error. 151 | - Missing state - 3rd party applications should ensure they are securely authenticating their users and thus should utilize state to protect against CSRF attacks. Not including state will result in a redirection with an appropriate error. 152 | 153 | **Success Behavior:** The user will be directed to the Cayenne authorization server for authentication. 154 | 155 | ##### Client Authentication and Approval Step 156 | 157 | The user will now login, if not already logged in as a Cayenne user. If they are already logged in due to the presence of a secured SSO cookie they will be forwarded to the next step. Otherwise, they will fill out a sign-in form and if they are able to authenticate correctly, allow access to the grants specified to the application. The following describes the behavior of success and error conditions: 158 | 159 | **Error behaviors:** 160 | 161 | - The user cannot login after multiple attempts- The request will be redirected back to the 3rd party application with the appropriate error 162 | - The user does not accept the applications request for user scope - The request will be redirected back to the application with the corresponding error. 163 | 164 | **Success behavior:** After successfully authenticating and accepting the requested scope, the user will be redirected back to the **redirect_uri** provided by the prior step in the following fashion: 165 | 166 | ``` 167 | ?access_token=&state= 168 | ``` 169 | 170 | **Query parameters:** 171 | 172 | - access_token - This is the JWT access token for the user. It can then be utilized directly against the resource server. 173 | - state - This state should be the same state value passed to the Cayenne Authorization server in the first step. If the client receives a different state than the one sent it should not continue the authorization process. 174 | 175 | #### Resource Owner and Refresh Token Grants 176 | 177 | Requests for Resource owner and Refresh token are handled by one endpoint by assigning **grant_type** to password or refresh_token. 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 |
POST/auth/realms/cayenne/protocol/openid-connect/token
187 | 188 | **Ressource Owner Parameters** 189 | 190 | | Parameter | Description | Type | 191 | |--------------------|--------------------|---| 192 | | email | email login for password grant type | String | 193 | | password | user password for password grant type | String | 194 | | refresh_token | Sent upon request of new access token | String | 195 | | client_id | used to identify which application/client id is being used for user | String | 196 | | client_secret | the secret key associated to the client id | String | 197 | | grant_type | defines grant type to route authentication (password) | String | 198 | | scope | scope of permissions requested | String | 199 | 200 | **Refresh Token Parameters** 201 | 202 | | Parameter | Description | Type | 203 | |--------------------|--------------------|---| 204 | | refresh_token | Sent upon request of new access token | String | 205 | | client_id | used to identify which application/client id is being used for user | String | 206 | | client_secret | the secret key associated to the client id | String | 207 | | grant_type | defines grant type to route authentication (refresh_token) | String | 208 | 209 | **Response Object and Messages** 210 | 211 | Success Response (200) 212 | 213 | ``` 214 | { 215 | “access_token”: “123456”, 216 | “refresh_token”: “123456” 217 | } 218 | ``` 219 | 220 | #### Curl example using Resource Owner Grant 221 | 222 | ``` 223 | curl -X POST --header 'Content-Type: application/x-www-form-urlencoded' --header 'Accept: application/json' -d 'grant_type=password&email=foobar%40example.com&password=example&client_id=123456' 'https://accounts.mydevices.com/auth/realms/cayenne/protocol/openid-connect/token' 224 | ``` 225 | 226 | #### Single Sign On 227 | 228 | Single sign on is provided for users as part of the authentication procedure. When a user has successfully logged in, the authorization server will create a secure cookie for that user only at the authorization domain. When the user returns to the authorization server whether for the same application or a different one, if the cookie is present, the user not be forced to login again and be redirected back to the source application as normal. This session will be valid for one week at which point the user will be forced to login again. 229 | -------------------------------------------------------------------------------- /docs/DOWNLOADS.md: -------------------------------------------------------------------------------- 1 | # Downloads 2 | 3 | 4 | 5 | 6 | ## Cayenne Arduino Library 7 | 8 | This library contains sketch files for microcontrollers which sends data to and from the Arduino hardware and Cayenne cloud for implementing incoming and outgoing commands, actions, triggers and alerts. 9 | 10 | * [Downloading and Installing the Cayenne Arduino Library](https://developers.mydevices.com/cayenne/docs/getting-started/#getting-started-arduino-arduino-setup-using-cayenne-arduino-library) 11 | 12 | ## Bring Your Own Thing Libraries 13 | 14 | The Cayenne BYOT API is used to connect your custom board with the Cayenne Cloud. After writing code to connect your board, you can send data from your device to the Cayenne dashboard and display it using widgets. You may also receive commands from Cayenne, allowing remote control and automation of your devices. The BYOT API currently supports MQTT in a variety of languages. 15 | 16 | * [BYOT Libraries](https://developers.mydevices.com/cayenne/docs/cayenne-mqtt-api/) 17 | -------------------------------------------------------------------------------- /docs/INTRO.md: -------------------------------------------------------------------------------- 1 | # Introduction 2 | 3 | This guide will help you to understand how to get started using Cayenne and give you the most comprehensive overview of all the features. If you want to jump straight into playing with Cayenne, check out [Getting Started](https://developers.mydevices.com/cayenne/docs/getting-started/).
4 | 5 |

6 | 7 | 8 | 9 | 10 | ## How Cayenne Works 11 | 12 | Cayenne is the world’s first drag and drop IoT project builder that empowers developers, designers and engineers to quickly prototype and share their connected device projects. Cayenne was designed to help users create Internet of Things prototypes and then bring them to production. 13 | 14 | The major component in the platform: 15 | 16 | - **Cayenne Online Dashboard** – Use customizable widgets to visualize data, set up rules, schedule events and more. 17 | 18 | 19 | 20 | 21 | ## What do I need? 22 | 23 | ### **Hardware** 24 | A Raspberry Pi or Arduino device connected to the Internet, or a LoRa device connected to a public or private gateway. The list of hardware that works with Cayenne will keep growing. 25 | 26 | ### **Browser** 27 | Cayenne is designed to work on popular browsers. 28 | 29 | \*Progressive Web Application(PWA) for iOS and Android coming soon. 30 | -------------------------------------------------------------------------------- /docs/IOTREADY.md: -------------------------------------------------------------------------------- 1 | # IoT Ready Program™ 2 | 3 | ## Overview 4 | 5 | Using the Cayenne IoT Ready Program™, you can enable your hardware with Cayenne, the world’s first IoT project builder created for developers and engineers to quickly design, prototype, and commercialize IoT solutions. 6 | 7 | - Give your customers a free tool to create solutions with your hardware. Your devices will be IoT-enabled with Cayenne features at no cost to you. 8 | - Your IoT ready hardware will be added to the Cayenne library accessible to thousands of developers that are already using Cayenne to build projects and solutions. 9 | - Your devices will seamlessly work with other devices. Developers will be empowered to design solutions by mixing-and-matching hardware to create IoT products. 10 | 11 | To get started, follow the [Enrollment process](#iot-ready-program-enrollment-sign-up) to create your free account. After creating your account you can [submit your hardware](#iot-ready-program-submitting-hardware-requests) for review and inclusion into Cayenne. 12 | 13 | ## Enrollment / Sign Up 14 | 15 | To join the IoT Ready Program, visit the Sign Up page. Fill in the details to begin creating your account and click on the **Submit** button to continue. 16 | 17 |


Sign up form

18 | 19 | After creating your account you will then be taken into your account on the IoT Ready Program website where you will need to read over and accept the licensing terms for the program and then fill out the information on your company, product and contacts. 20 | 21 | ### Company Information 22 | 23 | The information that you add to the company information form will not only be used by myDevices team when verifying your company, but will also be displayed on both the myDevices and Cayenne websites. You must complete the Company Information section before you can continue and submit devices to Cayenne. 24 | 25 | Be sure that the information you provide here is how you want it displayed to your users. In addition to the Partners page, your company name, description and logo may also be displayed to users as they select your hardware when using the Cayenne dashboard. 26 | 27 |


Company Information screen

28 | 29 | To help guide you in entering your company information correctly, it may help you to refer to some examples: 30 | 31 | - **Company Name:** be sure to enter in the name of your company, as you would it displayed to customers. 32 | - **Website:** be sure to enter in the website URL that you would like to be featured when customers wish to explore your company further. 33 | - **Description:** be sure to enter in a brief description of your company that customers can use to get a quick overview of your company. 34 | - **Logo:** be sure to upload an image file to be used when displaying your company’s logo. When customers view information on your company, or select your company’s hardware in Cayenne dashboard, they will see this logo. 35 | 36 | *TIP: We recommend using a high quality, 600x600 pixel image for the logo.* 37 | 38 |


myDevices Partners page

39 | 40 | After completing the company information you will be taken to your account [Home screen](#iot-ready-program-home-screen) where you can submit new hardware requests and view previous submissions. 41 | 42 | ## Home screen 43 | 44 | After logging into your account, you will see your account home screen. From here you can [submit new hardware requests](#iot-ready-program-submitting-hardware-requests) and [view past submissions](#iot-ready-program-viewing-submissions). 45 | 46 |


Account home screen

47 | 48 | ## Submitting hardware requests 49 | 50 | In order for your hardware to be included with Cayenne, you will need to submit a request. The Cayenne team will then review the information and test that the hardware is working with Cayenne. Once everything is approved and tested, your hardware will then be shown to all Cayenne users so that they can make use of it in their IoT products. 51 | 52 | *TIP: After submitting a request, you can always [view past submissions](#iot-ready-program-viewing-submissions) from your account and see the current status of your submission.* 53 | 54 | ### Submission Process Overview 55 | 56 | Regardless of which type of device you are submitting, the hardware submission and approval process is the same. Here’s what you can expect at each step of the process: 57 | 58 | 1. **Submission.** During this phase you’ll need to follow the [Hardware Submission Form](#iot-ready-program-submitting-hardware-requests-hardware-submission-form) which will walk you through providing all required device information to the myDevices team. You will also need to [send test hardware](#iot-ready-program-submitting-hardware-requests-sending-hardware-for-validation) to the myDevices team for validating connection to Cayenne. 59 | 2. **Reviewal.** During this phase the myDevices team will review that we have all the information needed for listing your Company and product in the dashboard. Once your test hardware is received, the team will test to verify it is working with Cayenne and is ready to be integrated. 60 | 61 | - **Verifying Company and Hardware information.** The myDevices team will verify that we have all required Company information as well as well information on the hardware to be integrated. If needed, you may be contacted by a member of the team for clarification or questions on supporting your device. 62 | - **Verification and testing of hardware.** Before your device can be integrated, testing will be performed to verify that the device is working properly with Cayenne. Submitting test hardware for verification is required as a part of the submission process. Be sure to have your hardware delivered promptly to the Cayenne team in order to minimize any delays in the approval process. 63 | - **Integration and operational testing.** The Cayenne team will start preparing to list your Company and product on the myDevices website and the Cayenne dashboard. 64 | 3. **Approval and Live.** After final verification from the myDevices and Cayenne teams, your device will then be made live. Users will then be able to select your hardware directly from the Cayenne dashboard. 65 | 66 | ### Starting A New Submission 67 | 68 | To begin the process of creating a new request, click on the **Submit New Hardware** button. The *Hardware Submission Form* will then appear. Follow the form and provide all needed information to submit your request. 69 | 70 |


Submit button highlighted

71 | 72 | ### Hardware Submission Form 73 | 74 | The Hardware Submission Form will guide you through entering in all information requested by the myDevices team. The information you provide during this process will help the team to understand your hardware, how it should be appropriately categorized into the Cayenne dashboard and how best to present it to end-users. It will also give the Cayenne team appropriate guidance on the technical details needed to verify a working connection to Cayenne and validate your product’s functionality with Cayenne. 75 | 76 | #### Connection Protocol 77 | 78 | To begin the submission process, you will need to first select how your product will connect with Cayenne. Your answer here will help steer the Hardware Submission Form in asking for the correct information during this process. 79 | 80 | - **LoRa:** Select this option if your product is a [LoRa technology device](#lora). During the [Setup and Configuration](#iot-ready-program-submitting-hardware-requests-hardware-submission-form-setup-and-configuration) portion of the submission process the form will ask you for more details [related to LoRa](https://developers.mydevices.com/cayenne/docs/iot-ready-program/#iot-ready-program-submitting-hardware-requests-hardware-submission-form-setup-and-configuration-lora-technology-device). 81 | - **MQTT:** Select this option if your product will communicate with Cayenne using [MQTT](https://developers.mydevices.com/cayenne/docs/iot-ready-program/#iot-ready-program-submitting-hardware-requests-hardware-submission-form-setup-and-configuration-mqtt), such as Cayenne’s [Bring Your Own Thing API](https://developers.mydevices.com/cayenne/docs/cayenne-mqtt-api/). During the [Setup and Configuration](#iot-ready-program-submitting-hardware-requests-hardware-submission-form-setup-and-configuration) portion of the submission process the form will ask you for more details [related to MQTT](#iot-ready-program-submitting-hardware-requests-hardware-submission-form-setup-and-configuration-mqtt). 82 | 83 |


Step 1 - Connection Protocol

84 | 85 | #### Device Info 86 | 87 | On the *Device Info* page you will enter in non-technical details for your product. This information will help guide the myDevices team when categorizing and adding your device into the Cayenne dashboard. Once added to the dashboard, the information you provide here may directly appear to end-users. To help guide you in entering in correct information, please see the information below and included examples showing where fields may appear in the dashboard. 88 | 89 |


Step 2 - Device Info

90 | 91 | - **Company Name:** This will be prefilled with your company name. Your device may be found in the Cayenne dashboard under your company name, so be sure that the name shown here is how you want it displayed to end users in the dashboard. 92 | - **Device Name:** The name of the device, as it will be shown to users when searching for and selecting your hardware. 93 | - **Device Photo Image:** This is the image that users see when selecting your hardware from the list in Cayenne. 94 | 95 | _NOTE: This image needs to be **600x600 pixels**. You may wish to refer to the Add Device process in Cayenne or the [Supported Hardware](https://developers.mydevices.com/cayenne/docs/supported-hardware/) documentation for examples of existing device images._ 96 | 97 | - **Datasheet, User Guides and Other Documentation:** Upload any datasheets, user guides, tutorials or other general documentation that you feel would be helpful for the Cayenne team to refer to on your hardware. 98 | 99 | - **Short Description of Device:** This short description is shown to users when they see the list of hardware to choose from. It helps guide users in understanding what the device is so that they select the most appropriate hardware from the list of devices. The space to display this information is limited, please select a description that is brief but adequately describes the device. Every piece of hardware in the Cayenne Add device process has this - you can refer to this for lots of examples. 100 | 101 | - **Device Website URL:** URL for the product page for your hardware. 102 | - **Device Purchase URL:** (If available) URL for a purchase page for your hardware. 103 | 104 |


Cayenne dashboard showing where information shows up

105 | 106 | #### Setup and Configuration 107 | 108 | On the *Setup and Configuration* page you will enter in some technical information on the hardware and configuration. This information will be used by the Cayenne team when the device is being tested and added into Cayenne. 109 | 110 | _TIP: During the process you may leave certain portions here unanswered (such as using the **Unknown** option) if that information is not available or not applicable. The goal for the Setup and Configuration section is to provide enough information to the Cayenne team that they can understand how the device works and so that they can verify it working with Cayenne. These are the same questions that our team would want answered before they implemented such a device themselves._ 111 | 112 | The type of information asked for here will depend upon how your device will connect to Cayenne. 113 | 114 | - [LoRa technology device](#iot-ready-program-submitting-hardware-requests-hardware-submission-form-setup-and-configuration-lora-technology-device): Start a new hardware submission for a device that uses LoRa technology. 115 | - [Device using MQTT](#iot-ready-program-submitting-hardware-requests-hardware-submission-form-setup-and-configuration-mqtt): Start a new hardware submission for a device that will communicate with Cayenne using [MQTT](https://developers.mydevices.com/cayenne/docs/cayenne-mqtt-api/), including Cayenne’s [Bring Your Own Thing API](https://developers.mydevices.com/cayenne/docs/cayenne-mqtt-api/). 116 | 117 | ##### LoRa technology device 118 | 119 |


Setup & Config screen showing LoRa fields

120 | 121 | - **Support LoRaWAN™ Bands:** Select which LoRaWAN band frequencies supported by your device. 122 | - **Device Unique Identifier:** Select whether your device supports a user-configurable [DevEUI](https://developers.mydevices.com/cayenne/docs/lora/#lora-about-deveuis). Certain development (e.g. prototype) devices will be configurable, meaning you can modify the device’s unique identifier. If the end user cannot do so, select the **Factory Set** option. 123 | - **LoRaWAN™ Activation:** Specify how your device connects to the LoRa network server. 124 | - **Available Configuration Apps:** If the device uses an app to program or configure the device, please enter in information on the platforms and programs used to do so. 125 | - **Sensor Data Types:** (If your device has embedded sensors) From the list of supported data types shown, select the list of data types that the device sends. By default you will see a list of the most commonly used data types. If you want the full list, click on the **All** link to view them all. To make finding data types easier, you can easily search for data types here. 126 | 127 |


Example Sensor Data Types

128 | 129 | ###### Payload Codecs 130 | 131 | - **Payload Codecs:** Select what payload format that your device uses to communicate its data. Cayenne needs to know which codec to use to properly decode and encode communication to and from your LoRa technology device. 132 | 133 |


Examples of existing codecs

134 | 135 | From the available list of codecs, choose one: 136 | 137 | - **Cayenne LPP:** Select this option if your device will use Cayenne’s own [generic Low Power Payload](https://developers.mydevices.com/cayenne/docs/lora/#lora-cayenne-low-power-payload). 138 | 139 | *TIP: We strongly recommend that you use Cayenne’s own LPP as it is the easiest way to get your LoRa technology device integrated with Cayenne. You can find all the information you need for using this payload in [Cayenne Low Power Payload](https://developers.mydevices.com/cayenne/docs/lora/#lora-cayenne-low-power-payload).* 140 | 141 | - **One of our already supported codecs:** If Cayenne already includes a codec for your payload format, you can select it from the list of available codecs. 142 | - **Use your own payload format**: If Cayenne does not currently support your device’s payload, select the **Custom** option. After doing so, you will be need to upload documentation that fully describes your payload format. The Cayenne team will then use this information to implement a payload codec that supports your format in Cayenne. 143 | 144 |


Custom codec and upload fields

145 | 146 | ##### MQTT 147 | 148 |


Setup & Config screen showing MQTT fields

149 | 150 | - **Sample Code Library:** Please specify the location (such as GitHub repository link) to where we can find sample code for connecting the device. It should give the user everything that they need to quickly and easily connect the device with Cayenne using MQTT. 151 | 152 | *TIP: Because the device will use MQTT, you can refer to our [Bring Your Own Thing API](https://developers.mydevices.com/cayenne/docs/cayenne-mqtt-api/) which gives you all the information you need to test connecting your device directly with Cayenne. Using the BYOT API and MQTT, you can easily verify your hardware is working with Cayenne prior to submitting your hardware request!* 153 | 154 | *Note: The code you provide will be displayed directly to the user in a popup window when they click on the example code button shown when adding your device in the Cayenne UI. This example code should be something that a user can copy & paste and use to easily connect that device to Cayenne.* 155 | 156 |


Example code popup in Cayenne

157 | 158 | - **Preferred IDE:** Optional. Provide us with information on what IDE is preferred to be used with the sample code provided. *Examples: Arduino IDE, mBed.* 159 | 160 | - **Internet Connection:** Tell us how the device connects to the Internet. 161 | - **Manufacturers Gateway:** Device must connect through a gateway that is supplied with the device. 162 | - **Ethernet extension:** Device requires an ethernet shield attached. 163 | - **Wi-Fi extension:** Device requires a Wi-Fi shield attached. 164 | - **Built in Wi-Fi:** Device has onboard Wi-Fi. 165 | 166 | #### Use cases 167 | 168 | In this optional section, we ask that you provide a short explanation of the purpose of your product and its use cases. This helps us to understand how your product is used and how it should best be described, classified and organized into Cayenne. 169 | 170 |


Step 4 Use Cases

171 | 172 | #### Review and Submit 173 | 174 | After filling out each section of the *Hardware Submission Form* you will see a summary view. From here you can review all information that has been entered. If you need to make any edits, you can easily do so from here by clicking on the **Edit** link to jump to that section and make any changes needed. 175 | 176 | When all sections have been filled out and you are ready to do so, click on the **Submit Device** button. After being submitted, the myDevices team will review the information and will get in touch with you if any additional information is required. 177 | 178 |


ALT

179 | 180 |


Submit device button highlight

181 | 182 | If you have additional devices you can use the **Submit Another Device** button to start the process of adding a new device. 183 | 184 | Don’t forget, you can use the [View Submissions](#iot-ready-program-viewing-submissions) link to view the current status of your submission. And remember to [send your hardware](#iot-ready-program-submitting-hardware-requests-sending-hardware-for-validation) to the Cayenne team so that they can complete the review and testing process - not doing so will delay the approval process. 185 | 186 | ### Sending Hardware for validation 187 | 188 | As a part of each new hardware submission, you will need to send test hardware to the myDevices team for validating connection to Cayenne. This process is required so that the myDevices team can verify a working connection with Cayenne. If necessary, this also allows the Cayenne team to write backend code, update our libraries, or perform other development tasks related to supporting your hardware. 189 | 190 | Please send at least 1 sample device to: 191 | 192 | ``` 193 | myDevices 194 | Attn: Camrin Roczey 195 | 23801 Calabasas Road, Ste. 2005 196 | Calabasas, CA 91302 197 | Phone: 818-436-3500 198 | ``` 199 | 200 | If you have any questions, contact us at IoTReady@myDevices.com 201 | 202 | ## Viewing Submissions 203 | 204 | You can view your past submitted hardware submissions at any time *Hardware Submission Status* screen. To access this screen, click on the **View Submissions** button located on your account home screen. 205 | 206 |


View Submissions button highlight

207 | 208 | From the *Hardware Submission Status* screen will be a list of all the past hardware submissions for your account along with their current status. From here you can: 209 | 210 | - Click on any device in the list of submission to [review its details](#iot-ready-program-viewing-submissions-reviewing-submission-details). 211 | - Review the current **Status** for your device submission. As your submission moves through the process, you may see different states shown here. 212 | 213 | - **Pending:** This is the default state that your submission will get when submitted. 214 | - **Approved:** Your submission has been received, reviewed and everything looks to be in order to bring your device into Cayenne. Note that questions may still come up when the Cayenne team integrates your device, so be on the lookout for any communications from the team in order to prevent any delays in getting your device added. 215 | - **Rejected:** Occasionally devices may need to be rejected for a variety of reasons. If this happens, you will be notified by email with more information and next steps on how to proceed. We’re happy to work with you to resolve the problems in order to get your hardware integrated successfully. 216 | 217 |


View Submissions screen with highlights

218 | 219 |


Submissions screen showing Approved example

220 | 221 | ### Reviewing submission details 222 | 223 | From the *Hardware Submission Status* screen you can review the details of your submission. To do so, simply click on the device entry in the list. The details of your submission will then be loaded so that you can review what was entered. 224 | 225 | *Note: After submitting your hardware the information shown here will be read only. If you need to update the myDevices team for any reason, please contact us at IoTReady@myDevices.com.* 226 | 227 |


Reviewing old submitted request

228 | -------------------------------------------------------------------------------- /docs/TINA.md: -------------------------------------------------------------------------------- 1 | # HTTP API 2 | 3 | Sending Device to Cloud messages using HTTP API. 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 |
POSTIoT in a Box: https://hub.m2c.io/v1/networks/iotinabox/uplink
Cayenne: https://hub.m2c.io/v1/networks/generic/uplink
13 | 14 | | Header | Value | 15 | |-------|-------------------------------------------| 16 | | Content-Type | application/json | 17 | | x-subscription-key | API Key | 18 | 19 | 20 | **Request Payload** 21 | ``` 22 | { 23 | "eui": "UNIQUE_DEVICE_ID", 24 | "format": "json", 25 | "data": { 26 | "temp": 20 27 | } 28 | } 29 | ``` 30 | 31 | **Request Example Using Cayenne LPP** 32 | ``` 33 | { 34 | "eui": "UNIQUE_DEVICE_ID", 35 | "format": "hex", 36 | "data": "0367014a046882" 37 | } 38 | ``` 39 | 40 | For Cayenne LPP Documentation 41 | 42 | **Request Example Using MQTT API Payload** 43 | ``` 44 | { 45 | "eui": "UNIQUE_DEVICE_ID", 46 | "format": "json", 47 | "data": [ 48 | { 49 | "channel": 1, 50 | "value": 16.4, 51 | "type": "temp", 52 | "unit": "c" 53 | }, 54 | { 55 | "channel": 2, 56 | "value": 75, 57 | "type": "rel_hum", 58 | "unit": "p" 59 | }, 60 | { 61 | "channel": 5, 62 | "value": 75, 63 | "type": "batt", 64 | "unit": "v" 65 | }, 66 | { 67 | "channel": 10, 68 | "value": 1, 69 | "type": "digital_sensor", 70 | "unit": "d" 71 | }, 72 | {...} 73 | ] 74 | } 75 | ``` 76 | 77 | The data property must be a JSON array of objects, each element having `channel`, `value`, `type` and `unit` porperties. Refer to the list of our supported data types for the `type` and `unit` properties. 78 | 79 | 80 | ## Image Upload API (Preview) 81 | 82 | The following endpoint consumes image stream and sensor data to be processed on myDevices platform. 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 |
POSThttps://hub.m2c.io/v1/networks/iotinabox/data
92 | 93 | **Headers** 94 | | Header | Value | 95 | |-------|-------------------------------------------| 96 | | Content-Type | multipart/form-data | 97 | | x-subscription-key | API Key | 98 | 99 | 100 | One of the part of the body should be set to `image` with the filename and additional parts can be sent with sensor data. The key would be the channel number `ch_x` and value would follow our MQTT channel based payload: `type,unit=value`. [Supported list of data types](https://github.com/myDevicesIoT/cayenne-docs/blob/master/docs/MQTTAPIS.md#supported-data-types) 101 | 102 | 103 | **Body** 104 | | Key | Value 105 | |-------|-------------------------------------------| 106 | | eui | fc0f860000000001f3 - Device ID | 107 | | snapshot | route65.jpg | 108 | | ch_1024 | file,image | 109 | | ch_x | type,unit=value | 110 | | ... | ... | 111 | 112 | 113 | 114 | **Example Curl Command** 115 | ```shell 116 | curl --request POST \ 117 | --url https://hub.m2c.io/v1/networks/iotinabox/data \ 118 | --header 'x-subscription-key: API-KEY' \ 119 | --header 'content-type: multipart/form-data' \ 120 | --form snapshot=@file.jpeg \ 121 | --form 'ch_1024=file,image=snapshot' \ 122 | --form 'ch_171=temp,f=75' \ 123 | --form 'ch_6=temp,f=75' \ 124 | --form 'ch_4=rel_hum,p=80' \ 125 | --form 'eui=fc0f860000000001f3' 126 | ``` 127 | 128 | # MQTT API 129 | 130 | ## V2 131 | 132 | ### Topic format 133 | 134 | All topics use following format : 135 | 136 | `v2/{serviceId}/{endpointId}/{resourceId}` 137 | 138 | Where 139 | - `serviceId` is the Cayenne MQTT API Service 140 | - `endpointId` is a Service endpoint 141 | - `resourceId` is a Cayenne MQTT API Resource 142 | 143 | ### Things Service 144 | 145 | | **Parameter** | **Definition** | 146 | |---------------|----------------| 147 | | `serviceId` | *things* | 148 | | `endpointId` | *Device ID* | 149 | 150 | 151 | ### Topic ACL 152 | 153 | ## Common Resources 154 | 155 | ### Data Resources 156 | | **resourceId** | **Payload** | **Description** | **V1** | **V2** | 157 | |------------------|-------------|--------------------------------------------------------------------|--------|--------| 158 | | `data/{CHANNEL}` | D_TEXT | Send value for a single sensor or actuator using text format. | ✅ | ✅ | 159 | | `data/json` | D_JSON | Send value for multiple sensors and actuators using Cayenne JSON. | ✅ | ❌ | 160 | | `data.json` | D_JSON | Send value for multiple sensors and actuators using Cayenne JSON. | ✅ | ✅ | 161 | | `data.bin` | LPP | Send value for multiple sensors and actuators using LPP binary format. | ❌ | ✅ | 162 | 163 | #### Example 164 | 165 | Publishing data to cloud 166 | 167 | **Topic*** 168 | `v2/things/DEVICE_ID/data.json` 169 | 170 | **Payload** 171 | ```json 172 | { 173 | "hardware_id": "01020304050607", 174 | "device_id" : "optinal", 175 | "client_id": "MQTT_USERNAME", 176 | "application_id": "REALM_TENANT_ID", 177 | "event": "uplink", 178 | "timestamp": 01020304050607, 179 | "sensors": [ 180 | { 181 | "channel": 1, 182 | "value": 16.4, 183 | "type": "temp", 184 | "unit": "c" 185 | }, 186 | { 187 | "channel": 2, 188 | "value": 75, 189 | "type": "rel_hum", 190 | "unit": "p" 191 | }, 192 | ... 193 | ] 194 | } 195 | ``` 196 | 197 | 198 | -------------------------------------------------------------------------------- /examples/MQTT_EthernetShieldW5100_with_TMP36/MQTT_EthernetShieldW5100_with_TMP36.ino: -------------------------------------------------------------------------------- 1 | // This example shows how to connect to the Cayenne MQTT broker using an Ethernet W5100 shield. It also includes 2 | // reading a TMP36 Temperature sensor's value, converting it to Temperature in Celsius and sending that data to Cayenne. 3 | 4 | //#define CAYENNE_DEBUG 5 | #define CAYENNE_PRINT Serial 6 | #include 7 | 8 | unsigned long lastMillis = 0; 9 | 10 | // Get these values from the Cayenne dashboard Connect screen for your new board 11 | char username[] = "Replace with MQTT Username from Connect screen"; 12 | char password[] = "Replace with MQTT Password from Connect screen"; 13 | char clientID[] = "Replace with CLIENT ID from Connect screen"; 14 | 15 | void setup() { 16 | Serial.begin(9600); 17 | Cayenne.begin(clientID, username, password); 18 | } 19 | 20 | void loop() { 21 | Cayenne.loop(); 22 | 23 | if(millis() - lastMillis > 10000) { 24 | lastMillis = millis(); 25 | 26 | // Read TMP36 sensor data from Analog Pin 0 and convert to a Celsius value. 27 | float voltage = 5.0; // we need to know the source voltage to convert properly below 28 | int reading = analogRead(0); // read voltage value from sensor 29 | float currentVoltage = (reading * voltage) / 1024.0; 30 | float currentTemp = (currentVoltage - 0.5) * 100; 31 | 32 | // Publish the TMP36 temperature data to Cayenne on Channel 0. 33 | Cayenne.celsiusWrite(0, currentTemp); 34 | } 35 | } 36 | 37 | CAYENNE_CONNECTED() 38 | { 39 | CAYENNE_LOG("CAYENNE_CONNECTED"); 40 | } 41 | 42 | CAYENNE_DISCONNECTED() 43 | { 44 | CAYENNE_LOG("CAYENNE_DISCONNECTED"); 45 | } 46 | 47 | CAYENNE_IN_DEFAULT() 48 | { 49 | CAYENNE_LOG("CAYENNE_IN_DEFAULT(%u) - %s, %s", request.pin, getValue.getId(), getValue.asString()); 50 | if (strcmp(getValue.asStr(), "error") == 0) { 51 | getValue.setError("Error message"); 52 | } 53 | } 54 | 55 | CAYENNE_OUT_DEFAULT() 56 | { 57 | CAYENNE_LOG("CAYENNE_OUT_DEFAULT(%u)", request.pin); 58 | } 59 | 60 | -------------------------------------------------------------------------------- /examples/README.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/myDevicesIoT/cayenne-docs/ff6da3d400d406a3cbc6b380abe3eeaa7009bbb9/examples/README.md -------------------------------------------------------------------------------- /img/expand.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/myDevicesIoT/cayenne-docs/ff6da3d400d406a3cbc6b380abe3eeaa7009bbb9/img/expand.png -------------------------------------------------------------------------------- /img/toggle.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/myDevicesIoT/cayenne-docs/ff6da3d400d406a3cbc6b380abe3eeaa7009bbb9/img/toggle.png -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | Cayenne Docs 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 49 | 50 | 119 | 120 | 121 | 122 | 123 | 124 | 188 | 189 | 190 | 191 |
192 | 195 |
196 |
197 | 198 | 199 | 200 | 201 | 202 | 203 | 211 | 212 | 213 | 214 | -------------------------------------------------------------------------------- /legacy.js: -------------------------------------------------------------------------------- 1 | /*! 2 | 3 | Support JS for legacy browsers. 4 | Includes: 5 | 6 | HTML5 Shiv 7 | @afarkas @jdalton @jon_neal @rem 8 | MIT/GPL2 Licensed 9 | https://github.com/aFarkas/html5shiv 10 | 11 | matchMedia() polyfill 12 | (c) 2012: Scott Jehl, Paul Irish, Nicholas Zakas. Dual MIT/BSD license 13 | 14 | Respond.js 15 | min/max-width media query polyfill 16 | (c) Scott Jehl. MIT/GPLv2 Lic. 17 | http://j.mp/respondjs 18 | 19 | */ 20 | /* 21 | HTML5 Shiv v3.6.2 | @afarkas @jdalton @jon_neal @rem | MIT/GPL2 Licensed 22 | */ 23 | (function(l,f){function m(){var a=e.elements;return"string"==typeof a?a.split(" "):a}function i(a){var b=n[a[o]];b||(b={},h++,a[o]=h,n[h]=b);return b}function p(a,b,c){b||(b=f);if(g)return b.createElement(a);c||(c=i(b));b=c.cache[a]?c.cache[a].cloneNode():r.test(a)?(c.cache[a]=c.createElem(a)).cloneNode():c.createElem(a);return b.canHaveChildren&&!s.test(a)?c.frag.appendChild(b):b}function t(a,b){if(!b.cache)b.cache={},b.createElem=a.createElement,b.createFrag=a.createDocumentFragment,b.frag=b.createFrag(); 24 | a.createElement=function(c){return!e.shivMethods?b.createElem(c):p(c,a,b)};a.createDocumentFragment=Function("h,f","return function(){var n=f.cloneNode(),c=n.createElement;h.shivMethods&&("+m().join().replace(/\w+/g,function(a){b.createElem(a);b.frag.createElement(a);return'c("'+a+'")'})+");return n}")(e,b.frag)}function q(a){a||(a=f);var b=i(a);if(e.shivCSS&&!j&&!b.hasCSS){var c,d=a;c=d.createElement("p");d=d.getElementsByTagName("head")[0]||d.documentElement;c.innerHTML="x"; 25 | c=d.insertBefore(c.lastChild,d.firstChild);b.hasCSS=!!c}g||t(a,b);return a}var k=l.html5||{},s=/^<|^(?:button|map|select|textarea|object|iframe|option|optgroup)$/i,r=/^(?:a|b|code|div|fieldset|h1|h2|h3|h4|h5|h6|i|label|li|ol|p|q|span|strong|style|table|tbody|td|th|tr|ul)$/i,j,o="_html5shiv",h=0,n={},g;(function(){try{var a=f.createElement("a");a.innerHTML="";j="hidden"in a;var b;if(!(b=1==a.childNodes.length)){f.createElement("a");var c=f.createDocumentFragment();b="undefined"==typeof c.cloneNode|| 26 | "undefined"==typeof c.createDocumentFragment||"undefined"==typeof c.createElement}g=b}catch(d){g=j=!0}})();var e={elements:k.elements||"abbr article aside audio bdi canvas data datalist details figcaption figure footer header hgroup main mark meter nav output progress section summary time video",version:"3.6.2",shivCSS:!1!==k.shivCSS,supportsUnknownElements:g,shivMethods:!1!==k.shivMethods,type:"default",shivDocument:q,createElement:p,createDocumentFragment:function(a,b){a||(a=f);if(g)return a.createDocumentFragment(); 27 | for(var b=b||i(a),c=b.frag.cloneNode(),d=0,e=m(),h=e.length;d 39 | fakeBody = doc.createElement( "body" ), 40 | div = doc.createElement( "div" ); 41 | 42 | div.id = "mq-test-1"; 43 | div.style.cssText = "position:absolute;top:-100em"; 44 | fakeBody.style.background = "none"; 45 | fakeBody.appendChild(div); 46 | 47 | return function(q){ 48 | 49 | div.innerHTML = "­"; 50 | 51 | docElem.insertBefore( fakeBody, refNode ); 52 | bool = div.offsetWidth === 42; 53 | docElem.removeChild( fakeBody ); 54 | 55 | return { 56 | matches: bool, 57 | media: q 58 | }; 59 | 60 | }; 61 | 62 | }( document )); 63 | 64 | 65 | 66 | 67 | 68 | /*! Respond.js v1.1.0: min/max-width media query polyfill. (c) Scott Jehl. MIT/GPLv2 Lic. j.mp/respondjs */ 69 | (function( win ){ 70 | 71 | "use strict"; 72 | 73 | //exposed namespace 74 | var respond = {}; 75 | win.respond = respond; 76 | 77 | //define update even in native-mq-supporting browsers, to avoid errors 78 | respond.update = function(){}; 79 | 80 | //expose media query support flag for external use 81 | respond.mediaQueriesSupported = win.matchMedia && win.matchMedia( "only all" ).matches; 82 | 83 | //if media queries are supported, exit here 84 | if( respond.mediaQueriesSupported ){ 85 | return; 86 | } 87 | 88 | //define vars 89 | var doc = win.document, 90 | docElem = doc.documentElement, 91 | mediastyles = [], 92 | rules = [], 93 | appendedEls = [], 94 | parsedSheets = {}, 95 | resizeThrottle = 30, 96 | head = doc.getElementsByTagName( "head" )[0] || docElem, 97 | base = doc.getElementsByTagName( "base" )[0], 98 | links = head.getElementsByTagName( "link" ), 99 | requestQueue = [], 100 | 101 | //loop stylesheets, send text content to translate 102 | ripCSS = function(){ 103 | 104 | for( var i = 0; i < links.length; i++ ){ 105 | var sheet = links[ i ], 106 | href = sheet.href, 107 | media = sheet.media, 108 | isCSS = sheet.rel && sheet.rel.toLowerCase() === "stylesheet"; 109 | 110 | //only links plz and prevent re-parsing 111 | if( !!href && isCSS && !parsedSheets[ href ] ){ 112 | // selectivizr exposes css through the rawCssText expando 113 | if (sheet.styleSheet && sheet.styleSheet.rawCssText) { 114 | translate( sheet.styleSheet.rawCssText, href, media ); 115 | parsedSheets[ href ] = true; 116 | } else { 117 | if( (!/^([a-zA-Z:]*\/\/)/.test( href ) && !base) || 118 | href.replace( RegExp.$1, "" ).split( "/" )[0] === win.location.host ){ 119 | requestQueue.push( { 120 | href: href, 121 | media: media 122 | } ); 123 | } 124 | } 125 | } 126 | } 127 | makeRequests(); 128 | }, 129 | 130 | //recurse through request queue, get css text 131 | makeRequests = function(){ 132 | if( requestQueue.length ){ 133 | var thisRequest = requestQueue.shift(); 134 | 135 | ajax( thisRequest.href, function( styles ){ 136 | translate( styles, thisRequest.href, thisRequest.media ); 137 | parsedSheets[ thisRequest.href ] = true; 138 | 139 | // by wrapping recursive function call in setTimeout 140 | // we prevent "Stack overflow" error in IE7 141 | win.setTimeout(function(){ makeRequests(); },0); 142 | } ); 143 | } 144 | }, 145 | 146 | //find media blocks in css text, convert to style blocks 147 | translate = function( styles, href, media ){ 148 | var qs = styles.match( /@media[^\{]+\{([^\{\}]*\{[^\}\{]*\})+/gi ), 149 | ql = qs && qs.length || 0; 150 | 151 | //try to get CSS path 152 | href = href.substring( 0, href.lastIndexOf( "/" ) ); 153 | 154 | var repUrls = function( css ){ 155 | return css.replace( /(url\()['"]?([^\/\)'"][^:\)'"]+)['"]?(\))/g, "$1" + href + "$2$3" ); 156 | }, 157 | useMedia = !ql && media; 158 | 159 | //if path exists, tack on trailing slash 160 | if( href.length ){ href += "/"; } 161 | 162 | //if no internal queries exist, but media attr does, use that 163 | //note: this currently lacks support for situations where a media attr is specified on a link AND 164 | //its associated stylesheet has internal CSS media queries. 165 | //In those cases, the media attribute will currently be ignored. 166 | if( useMedia ){ 167 | ql = 1; 168 | } 169 | 170 | for( var i = 0; i < ql; i++ ){ 171 | var fullq, thisq, eachq, eql; 172 | 173 | //media attr 174 | if( useMedia ){ 175 | fullq = media; 176 | rules.push( repUrls( styles ) ); 177 | } 178 | //parse for styles 179 | else{ 180 | fullq = qs[ i ].match( /@media *([^\{]+)\{([\S\s]+?)$/ ) && RegExp.$1; 181 | rules.push( RegExp.$2 && repUrls( RegExp.$2 ) ); 182 | } 183 | 184 | eachq = fullq.split( "," ); 185 | eql = eachq.length; 186 | 187 | for( var j = 0; j < eql; j++ ){ 188 | thisq = eachq[ j ]; 189 | mediastyles.push( { 190 | media : thisq.split( "(" )[ 0 ].match( /(only\s+)?([a-zA-Z]+)\s?/ ) && RegExp.$2 || "all", 191 | rules : rules.length - 1, 192 | hasquery : thisq.indexOf("(") > -1, 193 | minw : thisq.match( /\(\s*min\-width\s*:\s*(\s*[0-9\.]+)(px|em)\s*\)/ ) && parseFloat( RegExp.$1 ) + ( RegExp.$2 || "" ), 194 | maxw : thisq.match( /\(\s*max\-width\s*:\s*(\s*[0-9\.]+)(px|em)\s*\)/ ) && parseFloat( RegExp.$1 ) + ( RegExp.$2 || "" ) 195 | } ); 196 | } 197 | } 198 | 199 | applyMedia(); 200 | }, 201 | 202 | lastCall, 203 | 204 | resizeDefer, 205 | 206 | // returns the value of 1em in pixels 207 | getEmValue = function() { 208 | var ret, 209 | div = doc.createElement('div'), 210 | body = doc.body, 211 | fakeUsed = false; 212 | 213 | div.style.cssText = "position:absolute;font-size:1em;width:1em"; 214 | 215 | if( !body ){ 216 | body = fakeUsed = doc.createElement( "body" ); 217 | body.style.background = "none"; 218 | } 219 | 220 | body.appendChild( div ); 221 | 222 | docElem.insertBefore( body, docElem.firstChild ); 223 | 224 | ret = div.offsetWidth; 225 | 226 | if( fakeUsed ){ 227 | docElem.removeChild( body ); 228 | } 229 | else { 230 | body.removeChild( div ); 231 | } 232 | 233 | //also update eminpx before returning 234 | ret = eminpx = parseFloat(ret); 235 | 236 | return ret; 237 | }, 238 | 239 | //cached container for 1em value, populated the first time it's needed 240 | eminpx, 241 | 242 | //enable/disable styles 243 | applyMedia = function( fromResize ){ 244 | var name = "clientWidth", 245 | docElemProp = docElem[ name ], 246 | currWidth = doc.compatMode === "CSS1Compat" && docElemProp || doc.body[ name ] || docElemProp, 247 | styleBlocks = {}, 248 | lastLink = links[ links.length-1 ], 249 | now = (new Date()).getTime(); 250 | 251 | //throttle resize calls 252 | if( fromResize && lastCall && now - lastCall < resizeThrottle ){ 253 | win.clearTimeout( resizeDefer ); 254 | resizeDefer = win.setTimeout( applyMedia, resizeThrottle ); 255 | return; 256 | } 257 | else { 258 | lastCall = now; 259 | } 260 | 261 | for( var i in mediastyles ){ 262 | if( mediastyles.hasOwnProperty( i ) ){ 263 | var thisstyle = mediastyles[ i ], 264 | min = thisstyle.minw, 265 | max = thisstyle.maxw, 266 | minnull = min === null, 267 | maxnull = max === null, 268 | em = "em"; 269 | 270 | if( !!min ){ 271 | min = parseFloat( min ) * ( min.indexOf( em ) > -1 ? ( eminpx || getEmValue() ) : 1 ); 272 | } 273 | if( !!max ){ 274 | max = parseFloat( max ) * ( max.indexOf( em ) > -1 ? ( eminpx || getEmValue() ) : 1 ); 275 | } 276 | 277 | // if there's no media query at all (the () part), or min or max is not null, and if either is present, they're true 278 | if( !thisstyle.hasquery || ( !minnull || !maxnull ) && ( minnull || currWidth >= min ) && ( maxnull || currWidth <= max ) ){ 279 | if( !styleBlocks[ thisstyle.media ] ){ 280 | styleBlocks[ thisstyle.media ] = []; 281 | } 282 | styleBlocks[ thisstyle.media ].push( rules[ thisstyle.rules ] ); 283 | } 284 | } 285 | } 286 | 287 | //remove any existing respond style element(s) 288 | for( var j in appendedEls ){ 289 | if( appendedEls.hasOwnProperty( j ) ){ 290 | if( appendedEls[ j ] && appendedEls[ j ].parentNode === head ){ 291 | head.removeChild( appendedEls[ j ] ); 292 | } 293 | } 294 | } 295 | 296 | //inject active styles, grouped by media type 297 | for( var k in styleBlocks ){ 298 | if( styleBlocks.hasOwnProperty( k ) ){ 299 | var ss = doc.createElement( "style" ), 300 | css = styleBlocks[ k ].join( "\n" ); 301 | 302 | ss.type = "text/css"; 303 | ss.media = k; 304 | 305 | //originally, ss was appended to a documentFragment and sheets were appended in bulk. 306 | //this caused crashes in IE in a number of circumstances, such as when the HTML element had a bg image set, so appending beforehand seems best. Thanks to @dvelyk for the initial research on this one! 307 | head.insertBefore( ss, lastLink.nextSibling ); 308 | 309 | if ( ss.styleSheet ){ 310 | ss.styleSheet.cssText = css; 311 | } 312 | else { 313 | ss.appendChild( doc.createTextNode( css ) ); 314 | } 315 | 316 | //push to appendedEls to track for later removal 317 | appendedEls.push( ss ); 318 | } 319 | } 320 | }, 321 | //tweaked Ajax functions from Quirksmode 322 | ajax = function( url, callback ) { 323 | var req = xmlHttp(); 324 | if (!req){ 325 | return; 326 | } 327 | req.open( "GET", url, true ); 328 | req.onreadystatechange = function () { 329 | if ( req.readyState !== 4 || req.status !== 200 && req.status !== 304 ){ 330 | return; 331 | } 332 | callback( req.responseText ); 333 | }; 334 | if ( req.readyState === 4 ){ 335 | return; 336 | } 337 | req.send( null ); 338 | }, 339 | //define ajax obj 340 | xmlHttp = (function() { 341 | var xmlhttpmethod = false; 342 | try { 343 | xmlhttpmethod = new win.XMLHttpRequest(); 344 | } 345 | catch( e ){ 346 | xmlhttpmethod = new win.ActiveXObject( "Microsoft.XMLHTTP" ); 347 | } 348 | return function(){ 349 | return xmlhttpmethod; 350 | }; 351 | })(); 352 | 353 | //translate CSS 354 | ripCSS(); 355 | 356 | //expose update for re-running respond later on 357 | respond.update = ripCSS; 358 | 359 | //adjust on resize 360 | function callMedia(){ 361 | applyMedia( true ); 362 | } 363 | if( win.addEventListener ){ 364 | win.addEventListener( "resize", callMedia, false ); 365 | } 366 | else if( win.attachEvent ){ 367 | win.attachEvent( "onresize", callMedia ); 368 | } 369 | })(this); 370 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "flatdoc", 3 | "description": "Fetch Markdown files and render them as full pages.", 4 | "keywords": ["documentation", "markdown"], 5 | "author": "Rico Sta. Cruz ", 6 | "version": "0.9.0", 7 | "repository": { 8 | "type": "git", 9 | "url": "https://github.com/rstacruz/flatdoc.git" 10 | }, 11 | "scripts": { 12 | "test": "mocha" 13 | }, 14 | "main": "flatdoc.js", 15 | "devDependencies": { 16 | "mocha": "1.10.0", 17 | "chai": "1.6.0", 18 | "jsdom": "*", 19 | "uglify-js": "2.6.0", 20 | "stylus": "0.46.3", 21 | "nib": "0.9.1", 22 | "commander": "1.1.1", 23 | "dox": "0.4.3" 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /scrollspy.min.js: -------------------------------------------------------------------------------- 1 | !function(e,n){function o(e){return"object"===n.type(e)}function i(e){return"string"===n.type(e)&&n.trim(e).length>0}function t(e,n,o,i){i(e[o])||(e[o]=n[o])}n.fn.extend({scrollspy:function(l,s){if(i(l)){var a=s;s=l,l=a}l=n.extend({},r,l),t(l,r,"container",o);var c=n(l.container);if(0===c.length)return this;if(t(l,r,"namespace",i),i(s)&&"DESTROY"===s.toUpperCase())return c.off("scroll."+l.namespace),this;t(l,r,"buffer",n.isNumeric),t(l,r,"max",n.isNumeric),t(l,r,"min",n.isNumeric),t(l,r,"onEnter",n.isFunction),t(l,r,"onLeave",n.isFunction),t(l,r,"onLeaveTop",n.isFunction),t(l,r,"onLeaveBottom",n.isFunction),t(l,r,"onTick",n.isFunction),n.isFunction(l.max)&&(l.max=l.max()),n.isFunction(l.min)&&(l.min=l.min());var u="VERTICAL"===e.String(l.mode).toUpperCase();return this.each(function(){var e=this,o=n(e),i=0,t=!1,r=0;c.on("scroll."+l.namespace,function(){var s=n(this),a={top:s.scrollTop(),left:s.scrollLeft()},f=c.height(),p=l.max,m=l.min,v=u?a.top+l.buffer:a.left+l.buffer;if(0===p&&(p=u?f:c.outerWidth()+o.outerWidth()),v>=m&&p>=v)t||(t=!0,i++,o.trigger("scrollEnter",{position:a}),null!==l.onEnter&&l.onEnter(e,a)),o.trigger("scrollTick",{position:a,inside:t,enters:i,leaves:r}),null!==l.onTick&&l.onTick(e,a,t,i,r);else if(t)t=!1,r++,o.trigger("scrollLeave",{position:a,leaves:r}),null!==l.onLeave&&l.onLeave(e,a),m>=v?(o.trigger("scrollLeaveTop",{position:a,leaves:r}),null!==l.onLeaveTop&&l.onLeaveTop(e,a)):v>=p&&(o.trigger("scrollLeaveBottom",{position:a,leaves:r}),null!==l.onLeaveBottom&&l.onLeaveBottom(e,a));else{var g=c.scrollTop(),L=o.height(),h=o.offset().top;f+g>h&&h>g-L&&(o.trigger("scrollView",{position:a}),null!==l.onView&&l.onView(e,a))}})})}});var r={buffer:0,container:e,max:0,min:0,mode:"vertical",namespace:"scrollspy",onEnter:null,onLeave:null,onLeaveTop:null,onLeaveBottom:null,onTick:null,onView:null}}(window,window.jQuery); -------------------------------------------------------------------------------- /support/Notes.md: -------------------------------------------------------------------------------- 1 | Development notes 2 | ================= 3 | 4 | ### One-time setup 5 | You probably want to install the toolchain: 6 | 7 | $ npm install 8 | 9 | ### Auto-generate files 10 | This will (re-) build auto-generated files (stylus, etc). 11 | 12 | $ make 13 | $ make -B # Recompiles things 14 | 15 | ### Update vendor files 16 | This will download files. 17 | 18 | $ cd support/vendor/; make *.js 19 | 20 | ### Make a release 21 | This will concat/compress things into a build in `/v/0.8.0`. 22 | 23 | $ make v/0.8.0 24 | 25 | To do 26 | ----- 27 | 28 | - Sectioning 29 | -------------------------------------------------------------------------------- /support/blur.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/myDevicesIoT/cayenne-docs/ff6da3d400d406a3cbc6b380abe3eeaa7009bbb9/support/blur.jpg -------------------------------------------------------------------------------- /support/dox2md.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | var util = require('util'); 3 | var cli = require('commander'); 4 | 5 | cli 6 | .option('--private', 'Show privates') 7 | .option('--source', 'Show sources') 8 | .option('--debug', 'Print debug JSON') 9 | .option('--module-level [n]', 'Heading level for modules [2]', 2) 10 | .option('--default-level [n]', 'Heading level for everything [3]', 3) 11 | .option('--lang ', 'Sets highlight block language [js]', 'js') 12 | .on('--help', function() { 13 | console.log(' Basic use:'); 14 | console.log(''); 15 | console.log(' $ dox -r < file.js | dox2md > out'); 16 | process.exit(0); 17 | }); 18 | cli.parse(process.argv); 19 | 20 | readStdin(function(json) { 21 | var blocks = JSON.parse(json); 22 | var lines = []; 23 | 24 | blocks = removeBlocks(blocks, function(b) { return !b.ignore; }); 25 | 26 | if (!cli['private']) 27 | blocks = removeBlocks(blocks, function(b) { return !b.isPrivate; }); 28 | 29 | // Definitions 30 | blocks.forEach(function(block, i) { 31 | if (!block.ctx) return; 32 | lines.push(markdownify(block, i, cli)); 33 | }); 34 | 35 | // Jump links 36 | lines.push(""); 37 | blocks.forEach(function(block, i) { 38 | if (!block.ctx) return; 39 | var name = namify(block.ctx); 40 | lines.push('[' + name + ']: #' + slugify(name)); 41 | }); 42 | 43 | if (cli.debug) 44 | process.stderr.write(util.inspect(blocks, false, Infinity, true)); 45 | 46 | console.log(lines.join("\n")); 47 | }); 48 | 49 | function markdownify(block, i, options) { 50 | var lines = []; 51 | var name = namify(block.ctx); 52 | var level; 53 | 54 | // Heading 55 | if (i === 0) { level = 1; } 56 | else if (isModule(name)) { level = options.moduleLevel; } 57 | else { level = options.defaultLevel; } 58 | lines.push(heading(name, level)); 59 | lines.push(fixMarkdown(block.description.full, options.lang)); 60 | lines.push(""); 61 | 62 | // Sources 63 | if (options.source) { 64 | lines.push("> Source:", "", codeBlock(block.code, options.lang)); 65 | } 66 | 67 | return lines.join("\n"); 68 | } 69 | 70 | function fixMarkdown(buf, lang) { 71 | var code = buf.match(/^( {4}[^\n]+\n*)+/gm) || []; 72 | 73 | code.forEach(function(block){ 74 | var code = block.replace(/^ {4}/gm, ''); 75 | buf = buf.replace(block, codeBlock(code, lang)); 76 | }); 77 | 78 | return buf; 79 | } 80 | 81 | function codeBlock(code, lang) { 82 | return '```'+lang+'\n' + code.trimRight() + '\n```\n\n'; 83 | } 84 | 85 | // Returns the name for a given context. 86 | function namify(ctx) { 87 | return ctx.string 88 | .replace('.prototype.', '#'); 89 | } 90 | 91 | // Checks if a given name is a module. 92 | function isModule(name) { 93 | return !! name.match(/^[A-Za-z][A-Za-z0-9_]*$/); 94 | } 95 | 96 | function heading(str, level) { 97 | if (level === 1) return str + "\n" + times("=", str.length) + "\n"; 98 | if (level === 2) return str + "\n" + times("-", str.length) + "\n"; 99 | return times('#', level) + ' ' + str + "\n"; 100 | } 101 | 102 | function times(str, n) { 103 | var re = ''; 104 | for (var i=0; i .in { 20 | display: table-cell; 21 | vertical-align: middle; } 22 | 23 | .title-card .headline { 24 | vertical-align: middle; 25 | display: inline-block; 26 | -webkit-box-sizing: border-box; 27 | box-sizing: border-box; 28 | 29 | /* text-shadow: 0 0 4px rgba(0, 0, 0, 0.5); */ 30 | 31 | padding-left: 40px; 32 | padding-right: 40px; 33 | max-width: 800px; 34 | line-height: 1.7; } 35 | 36 | .title-card h1 { 37 | font-family: 'Open Sans', sans-serif; 38 | font-size: 3.3em; 39 | font-weight: 300; 40 | line-height: 1.1; 41 | margin-bottom: 0.5em; 42 | color: #fff; } 43 | 44 | .title-card p { 45 | font-family: montserrat, sans-serif; 46 | color: #b8eaea; 47 | font-weight: bold; 48 | font-size: 1.3em; } 49 | 50 | .title-card h5 { 51 | margin-top: 150px; 52 | 53 | font-family: montserrat, sans-serif; 54 | font-weight: bold; 55 | color: #fff; 56 | text-transform: uppercase; 57 | letter-spacing: 2px; 58 | font-size: 1.8em; } 59 | 60 | .title-card h5 span { 61 | display: inline-block; 62 | padding: 5px 20px; 63 | border: solid 3px #fff; } 64 | 65 | @media (max-width: 768px) /* Tablet */ { 66 | .title-card h5 { 67 | margin-top: 100px; } 68 | } 69 | 70 | @media (max-width: 480px) /* Mobile */ { 71 | .title-card { 72 | padding: 50px 0; } 73 | .title-card .headline { 74 | padding-left: 10px; 75 | padding-right: 10px; 76 | min-height: none; } 77 | .title-card h1 { 78 | font-size: 2.2em; } 79 | .title-card p { 80 | font-size: 1.1em; } 81 | .title-card h5 { 82 | margin-top: 40px; 83 | font-size: 0.9em; } 84 | } 85 | -------------------------------------------------------------------------------- /support/theme.js: -------------------------------------------------------------------------------- 1 | (function($) { 2 | 3 | $(document).on('flatdoc:ready', function() { 4 | $("#misc, #basic").remove(); 5 | 6 | $("pre > code").each(function() { 7 | var $code = $(this); 8 | var m = $code.text().match(/Toggle"); 11 | $q.find('a').click(function() { 12 | var klass = $(this).attr('href').substr(1); 13 | $('body').toggleClass(klass); 14 | if (klass === 'big-h3') $.anchorjump('#theme-options'); 15 | if (klass === 'large-brief') $.anchorjump('#flatdoc'); 16 | 17 | }); 18 | $code.after($q); 19 | } 20 | }); 21 | }); 22 | 23 | })(jQuery); 24 | -------------------------------------------------------------------------------- /support/vendor/Makefile: -------------------------------------------------------------------------------- 1 | html5shiv.js: 2 | wget "https://raw.github.com/aFarkas/html5shiv/master/dist/html5shiv.js" -q -O $@ 3 | 4 | marked.js: 5 | wget "https://github.com/chjj/marked/raw/master/lib/marked.js" -q -O $@ 6 | 7 | respond.js: 8 | wget "https://github.com/scottjehl/Respond/raw/master/respond.src.js" -q -O $@ 9 | 10 | jquery.js: 11 | wget "http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js" -q -O $@ 12 | 13 | jquery.scrollagent.js: 14 | wget "https://github.com/rstacruz/jquery-stuff/raw/master/scrollagent/jquery.scrollagent.js" -q -O $@ 15 | 16 | jquery.anchorjump.js: 17 | wget "https://github.com/rstacruz/jquery-stuff/raw/master/anchorjump/jquery.anchorjump.js" -q -O $@ 18 | 19 | jquery.fillsize.js: 20 | wget "https://github.com/rstacruz/jquery-stuff/raw/master/fillsize/jquery.fillsize.js" -q -O $@ 21 | 22 | base64.js: 23 | wget "https://raw.github.com/dankogai/js-base64/master/base64.js" -q -O $@ 24 | -------------------------------------------------------------------------------- /support/vendor/html5shiv.js: -------------------------------------------------------------------------------- 1 | /* 2 | HTML5 Shiv v3.6.2 | @afarkas @jdalton @jon_neal @rem | MIT/GPL2 Licensed 3 | */ 4 | (function(l,f){function m(){var a=e.elements;return"string"==typeof a?a.split(" "):a}function i(a){var b=n[a[o]];b||(b={},h++,a[o]=h,n[h]=b);return b}function p(a,b,c){b||(b=f);if(g)return b.createElement(a);c||(c=i(b));b=c.cache[a]?c.cache[a].cloneNode():r.test(a)?(c.cache[a]=c.createElem(a)).cloneNode():c.createElem(a);return b.canHaveChildren&&!s.test(a)?c.frag.appendChild(b):b}function t(a,b){if(!b.cache)b.cache={},b.createElem=a.createElement,b.createFrag=a.createDocumentFragment,b.frag=b.createFrag(); 5 | a.createElement=function(c){return!e.shivMethods?b.createElem(c):p(c,a,b)};a.createDocumentFragment=Function("h,f","return function(){var n=f.cloneNode(),c=n.createElement;h.shivMethods&&("+m().join().replace(/\w+/g,function(a){b.createElem(a);b.frag.createElement(a);return'c("'+a+'")'})+");return n}")(e,b.frag)}function q(a){a||(a=f);var b=i(a);if(e.shivCSS&&!j&&!b.hasCSS){var c,d=a;c=d.createElement("p");d=d.getElementsByTagName("head")[0]||d.documentElement;c.innerHTML="x"; 6 | c=d.insertBefore(c.lastChild,d.firstChild);b.hasCSS=!!c}g||t(a,b);return a}var k=l.html5||{},s=/^<|^(?:button|map|select|textarea|object|iframe|option|optgroup)$/i,r=/^(?:a|b|code|div|fieldset|h1|h2|h3|h4|h5|h6|i|label|li|ol|p|q|span|strong|style|table|tbody|td|th|tr|ul)$/i,j,o="_html5shiv",h=0,n={},g;(function(){try{var a=f.createElement("a");a.innerHTML="";j="hidden"in a;var b;if(!(b=1==a.childNodes.length)){f.createElement("a");var c=f.createDocumentFragment();b="undefined"==typeof c.cloneNode|| 7 | "undefined"==typeof c.createDocumentFragment||"undefined"==typeof c.createElement}g=b}catch(d){g=j=!0}})();var e={elements:k.elements||"abbr article aside audio bdi canvas data datalist details figcaption figure footer header hgroup main mark meter nav output progress section summary time video",version:"3.6.2",shivCSS:!1!==k.shivCSS,supportsUnknownElements:g,shivMethods:!1!==k.shivMethods,type:"default",shivDocument:q,createElement:p,createDocumentFragment:function(a,b){a||(a=f);if(g)return a.createDocumentFragment(); 8 | for(var b=b||i(a),c=b.frag.cloneNode(),d=0,e=m(),h=e.length;d img"); 7 | // 8 | // This binds a listener on window resizing to automatically scale down the 9 | // child (`> img` in this example) just so that enough of it will be visible in 10 | // the viewport of the container. 11 | // 12 | // This assumes that the container has `position: relative` (or any 'position', 13 | // really), and `overflow: hidden`. 14 | 15 | (function($) { 16 | $.fn.fillsize = function(selector) { 17 | var $parent = this; 18 | var $img; 19 | 20 | function resize() { 21 | if (!$img) $img = $parent.find(selector); 22 | 23 | $img.each(function() { 24 | if (!this.complete) return; 25 | var $img = $(this); 26 | 27 | var parent = { height: $parent.innerHeight(), width: $parent.innerWidth() }; 28 | var imageRatio = $img.width() / $img.height(); 29 | var containerRatio = parent.width / parent.height; 30 | 31 | var css = { 32 | position: 'absolute', 33 | left: 0, top: 0, right: 'auto', bottom: 'auto' 34 | }; 35 | 36 | // If image is wider than the container 37 | if (imageRatio > containerRatio) { 38 | css.left = Math.round((parent.width - imageRatio * parent.height) / 2) + 'px'; 39 | css.width = 'auto'; 40 | css.height = '100%'; 41 | } 42 | 43 | // If the container is wider than the image 44 | else { 45 | css.top = Math.round((parent.height - (parent.width / $img.width() * $img.height())) / 2) + 'px'; 46 | css.height = 'auto'; 47 | css.width = '100%'; 48 | } 49 | 50 | $img.css(css); 51 | }); 52 | } 53 | 54 | // Make it happen on window resize. 55 | $(window).resize(resize); 56 | 57 | // Allow manual invocation by doing `.trigger('fillsize')` on the container. 58 | $(document).on('fillsize', $parent.selector, resize); 59 | 60 | // Resize on first load (or immediately if called after). 61 | $(function() { 62 | // If the child is an image, fill it up when image's real dimensions are 63 | // first determined. Needs to be .bind() because the load event will 64 | // bubble up. 65 | $(selector, $parent).bind('load', function() { 66 | setTimeout(resize, 25); 67 | }); 68 | 69 | resize(); 70 | }); 71 | 72 | return this; 73 | }; 74 | })(jQuery); 75 | -------------------------------------------------------------------------------- /support/vendor/jquery.smartquotes.js: -------------------------------------------------------------------------------- 1 | /*! Smartquotes (c) 2012, Rico Sta. Cruz. MIT License. 2 | * http://github.com/rstacruz/jquery-stuff/tree/master/smartquotes */ 3 | 4 | // Translates plain ASCII punctuation characters into typographic punctuation 5 | // HTML entities. Inspired by Smartypants. 6 | // 7 | // $(function() { 8 | // $("body").smartquotes(); 9 | // }); 10 | // 11 | (function($) { 12 | // http://www.leancrew.com/all-this/2010/11/smart-quotes-in-javascript/ 13 | $.smartquotes = function(a) { 14 | a = a.replace(/(^|[-\u2014\s(\["])'/g, "$1\u2018"); // opening singles 15 | a = a.replace(/'/g, "\u2019"); // closing singles & apostrophes 16 | a = a.replace(/(^|[-\u2014/\[(\u2018\s])"/g, "$1\u201c"); // opening doubles 17 | a = a.replace(/"/g, "\u201d"); // closing doubles 18 | a = a.replace(/\.\.\./g, "\u2026"); // ellipses 19 | a = a.replace(/--/g, "\u2014"); // em-dashes 20 | return a; 21 | }; 22 | 23 | // http://stackoverflow.com/questions/298750/how-do-i-select-text-nodes-with-jquery 24 | function getTextNodesIn(el) { 25 | return $(el).find(":not(iframe,pre,code)").andSelf().contents().filter(function() { 26 | return this.nodeType == 3; 27 | }); 28 | } 29 | 30 | $.fn.smartquotes = function(fn) { 31 | if (!fn) fn = $.smartquotes; 32 | 33 | var nodes = getTextNodesIn(this); 34 | for (var i in nodes) { 35 | if (nodes.hasOwnProperty(i)) { 36 | var node = nodes[i]; 37 | node.nodeValue = fn(node.nodeValue); 38 | } 39 | } 40 | }; 41 | })(jQuery); 42 | -------------------------------------------------------------------------------- /support/vendor/respond.js: -------------------------------------------------------------------------------- 1 | /*! matchMedia() polyfill - Test a CSS media type/query in JS. Authors & copyright (c) 2012: Scott Jehl, Paul Irish, Nicholas Zakas. Dual MIT/BSD license */ 2 | /*! NOTE: If you're already including a window.matchMedia polyfill via Modernizr or otherwise, you don't need this part */ 3 | 4 | window.matchMedia = window.matchMedia || (function( doc, undefined ) { 5 | 6 | "use strict"; 7 | 8 | var bool, 9 | docElem = doc.documentElement, 10 | refNode = docElem.firstElementChild || docElem.firstChild, 11 | // fakeBody required for 12 | fakeBody = doc.createElement( "body" ), 13 | div = doc.createElement( "div" ); 14 | 15 | div.id = "mq-test-1"; 16 | div.style.cssText = "position:absolute;top:-100em"; 17 | fakeBody.style.background = "none"; 18 | fakeBody.appendChild(div); 19 | 20 | return function(q){ 21 | 22 | div.innerHTML = "­"; 23 | 24 | docElem.insertBefore( fakeBody, refNode ); 25 | bool = div.offsetWidth === 42; 26 | docElem.removeChild( fakeBody ); 27 | 28 | return { 29 | matches: bool, 30 | media: q 31 | }; 32 | 33 | }; 34 | 35 | }( document )); 36 | 37 | 38 | 39 | 40 | 41 | /*! Respond.js v1.1.0: min/max-width media query polyfill. (c) Scott Jehl. MIT/GPLv2 Lic. j.mp/respondjs */ 42 | (function( win ){ 43 | 44 | "use strict"; 45 | 46 | //exposed namespace 47 | var respond = {}; 48 | win.respond = respond; 49 | 50 | //define update even in native-mq-supporting browsers, to avoid errors 51 | respond.update = function(){}; 52 | 53 | //expose media query support flag for external use 54 | respond.mediaQueriesSupported = win.matchMedia && win.matchMedia( "only all" ).matches; 55 | 56 | //if media queries are supported, exit here 57 | if( respond.mediaQueriesSupported ){ 58 | return; 59 | } 60 | 61 | //define vars 62 | var doc = win.document, 63 | docElem = doc.documentElement, 64 | mediastyles = [], 65 | rules = [], 66 | appendedEls = [], 67 | parsedSheets = {}, 68 | resizeThrottle = 30, 69 | head = doc.getElementsByTagName( "head" )[0] || docElem, 70 | base = doc.getElementsByTagName( "base" )[0], 71 | links = head.getElementsByTagName( "link" ), 72 | requestQueue = [], 73 | 74 | //loop stylesheets, send text content to translate 75 | ripCSS = function(){ 76 | 77 | for( var i = 0; i < links.length; i++ ){ 78 | var sheet = links[ i ], 79 | href = sheet.href, 80 | media = sheet.media, 81 | isCSS = sheet.rel && sheet.rel.toLowerCase() === "stylesheet"; 82 | 83 | //only links plz and prevent re-parsing 84 | if( !!href && isCSS && !parsedSheets[ href ] ){ 85 | // selectivizr exposes css through the rawCssText expando 86 | if (sheet.styleSheet && sheet.styleSheet.rawCssText) { 87 | translate( sheet.styleSheet.rawCssText, href, media ); 88 | parsedSheets[ href ] = true; 89 | } else { 90 | if( (!/^([a-zA-Z:]*\/\/)/.test( href ) && !base) || 91 | href.replace( RegExp.$1, "" ).split( "/" )[0] === win.location.host ){ 92 | requestQueue.push( { 93 | href: href, 94 | media: media 95 | } ); 96 | } 97 | } 98 | } 99 | } 100 | makeRequests(); 101 | }, 102 | 103 | //recurse through request queue, get css text 104 | makeRequests = function(){ 105 | if( requestQueue.length ){ 106 | var thisRequest = requestQueue.shift(); 107 | 108 | ajax( thisRequest.href, function( styles ){ 109 | translate( styles, thisRequest.href, thisRequest.media ); 110 | parsedSheets[ thisRequest.href ] = true; 111 | 112 | // by wrapping recursive function call in setTimeout 113 | // we prevent "Stack overflow" error in IE7 114 | win.setTimeout(function(){ makeRequests(); },0); 115 | } ); 116 | } 117 | }, 118 | 119 | //find media blocks in css text, convert to style blocks 120 | translate = function( styles, href, media ){ 121 | var qs = styles.match( /@media[^\{]+\{([^\{\}]*\{[^\}\{]*\})+/gi ), 122 | ql = qs && qs.length || 0; 123 | 124 | //try to get CSS path 125 | href = href.substring( 0, href.lastIndexOf( "/" ) ); 126 | 127 | var repUrls = function( css ){ 128 | return css.replace( /(url\()['"]?([^\/\)'"][^:\)'"]+)['"]?(\))/g, "$1" + href + "$2$3" ); 129 | }, 130 | useMedia = !ql && media; 131 | 132 | //if path exists, tack on trailing slash 133 | if( href.length ){ href += "/"; } 134 | 135 | //if no internal queries exist, but media attr does, use that 136 | //note: this currently lacks support for situations where a media attr is specified on a link AND 137 | //its associated stylesheet has internal CSS media queries. 138 | //In those cases, the media attribute will currently be ignored. 139 | if( useMedia ){ 140 | ql = 1; 141 | } 142 | 143 | for( var i = 0; i < ql; i++ ){ 144 | var fullq, thisq, eachq, eql; 145 | 146 | //media attr 147 | if( useMedia ){ 148 | fullq = media; 149 | rules.push( repUrls( styles ) ); 150 | } 151 | //parse for styles 152 | else{ 153 | fullq = qs[ i ].match( /@media *([^\{]+)\{([\S\s]+?)$/ ) && RegExp.$1; 154 | rules.push( RegExp.$2 && repUrls( RegExp.$2 ) ); 155 | } 156 | 157 | eachq = fullq.split( "," ); 158 | eql = eachq.length; 159 | 160 | for( var j = 0; j < eql; j++ ){ 161 | thisq = eachq[ j ]; 162 | mediastyles.push( { 163 | media : thisq.split( "(" )[ 0 ].match( /(only\s+)?([a-zA-Z]+)\s?/ ) && RegExp.$2 || "all", 164 | rules : rules.length - 1, 165 | hasquery : thisq.indexOf("(") > -1, 166 | minw : thisq.match( /\(\s*min\-width\s*:\s*(\s*[0-9\.]+)(px|em)\s*\)/ ) && parseFloat( RegExp.$1 ) + ( RegExp.$2 || "" ), 167 | maxw : thisq.match( /\(\s*max\-width\s*:\s*(\s*[0-9\.]+)(px|em)\s*\)/ ) && parseFloat( RegExp.$1 ) + ( RegExp.$2 || "" ) 168 | } ); 169 | } 170 | } 171 | 172 | applyMedia(); 173 | }, 174 | 175 | lastCall, 176 | 177 | resizeDefer, 178 | 179 | // returns the value of 1em in pixels 180 | getEmValue = function() { 181 | var ret, 182 | div = doc.createElement('div'), 183 | body = doc.body, 184 | fakeUsed = false; 185 | 186 | div.style.cssText = "position:absolute;font-size:1em;width:1em"; 187 | 188 | if( !body ){ 189 | body = fakeUsed = doc.createElement( "body" ); 190 | body.style.background = "none"; 191 | } 192 | 193 | body.appendChild( div ); 194 | 195 | docElem.insertBefore( body, docElem.firstChild ); 196 | 197 | ret = div.offsetWidth; 198 | 199 | if( fakeUsed ){ 200 | docElem.removeChild( body ); 201 | } 202 | else { 203 | body.removeChild( div ); 204 | } 205 | 206 | //also update eminpx before returning 207 | ret = eminpx = parseFloat(ret); 208 | 209 | return ret; 210 | }, 211 | 212 | //cached container for 1em value, populated the first time it's needed 213 | eminpx, 214 | 215 | //enable/disable styles 216 | applyMedia = function( fromResize ){ 217 | var name = "clientWidth", 218 | docElemProp = docElem[ name ], 219 | currWidth = doc.compatMode === "CSS1Compat" && docElemProp || doc.body[ name ] || docElemProp, 220 | styleBlocks = {}, 221 | lastLink = links[ links.length-1 ], 222 | now = (new Date()).getTime(); 223 | 224 | //throttle resize calls 225 | if( fromResize && lastCall && now - lastCall < resizeThrottle ){ 226 | win.clearTimeout( resizeDefer ); 227 | resizeDefer = win.setTimeout( applyMedia, resizeThrottle ); 228 | return; 229 | } 230 | else { 231 | lastCall = now; 232 | } 233 | 234 | for( var i in mediastyles ){ 235 | if( mediastyles.hasOwnProperty( i ) ){ 236 | var thisstyle = mediastyles[ i ], 237 | min = thisstyle.minw, 238 | max = thisstyle.maxw, 239 | minnull = min === null, 240 | maxnull = max === null, 241 | em = "em"; 242 | 243 | if( !!min ){ 244 | min = parseFloat( min ) * ( min.indexOf( em ) > -1 ? ( eminpx || getEmValue() ) : 1 ); 245 | } 246 | if( !!max ){ 247 | max = parseFloat( max ) * ( max.indexOf( em ) > -1 ? ( eminpx || getEmValue() ) : 1 ); 248 | } 249 | 250 | // if there's no media query at all (the () part), or min or max is not null, and if either is present, they're true 251 | if( !thisstyle.hasquery || ( !minnull || !maxnull ) && ( minnull || currWidth >= min ) && ( maxnull || currWidth <= max ) ){ 252 | if( !styleBlocks[ thisstyle.media ] ){ 253 | styleBlocks[ thisstyle.media ] = []; 254 | } 255 | styleBlocks[ thisstyle.media ].push( rules[ thisstyle.rules ] ); 256 | } 257 | } 258 | } 259 | 260 | //remove any existing respond style element(s) 261 | for( var j in appendedEls ){ 262 | if( appendedEls.hasOwnProperty( j ) ){ 263 | if( appendedEls[ j ] && appendedEls[ j ].parentNode === head ){ 264 | head.removeChild( appendedEls[ j ] ); 265 | } 266 | } 267 | } 268 | 269 | //inject active styles, grouped by media type 270 | for( var k in styleBlocks ){ 271 | if( styleBlocks.hasOwnProperty( k ) ){ 272 | var ss = doc.createElement( "style" ), 273 | css = styleBlocks[ k ].join( "\n" ); 274 | 275 | ss.type = "text/css"; 276 | ss.media = k; 277 | 278 | //originally, ss was appended to a documentFragment and sheets were appended in bulk. 279 | //this caused crashes in IE in a number of circumstances, such as when the HTML element had a bg image set, so appending beforehand seems best. Thanks to @dvelyk for the initial research on this one! 280 | head.insertBefore( ss, lastLink.nextSibling ); 281 | 282 | if ( ss.styleSheet ){ 283 | ss.styleSheet.cssText = css; 284 | } 285 | else { 286 | ss.appendChild( doc.createTextNode( css ) ); 287 | } 288 | 289 | //push to appendedEls to track for later removal 290 | appendedEls.push( ss ); 291 | } 292 | } 293 | }, 294 | //tweaked Ajax functions from Quirksmode 295 | ajax = function( url, callback ) { 296 | var req = xmlHttp(); 297 | if (!req){ 298 | return; 299 | } 300 | req.open( "GET", url, true ); 301 | req.onreadystatechange = function () { 302 | if ( req.readyState !== 4 || req.status !== 200 && req.status !== 304 ){ 303 | return; 304 | } 305 | callback( req.responseText ); 306 | }; 307 | if ( req.readyState === 4 ){ 308 | return; 309 | } 310 | req.send( null ); 311 | }, 312 | //define ajax obj 313 | xmlHttp = (function() { 314 | var xmlhttpmethod = false; 315 | try { 316 | xmlhttpmethod = new win.XMLHttpRequest(); 317 | } 318 | catch( e ){ 319 | xmlhttpmethod = new win.ActiveXObject( "Microsoft.XMLHTTP" ); 320 | } 321 | return function(){ 322 | return xmlhttpmethod; 323 | }; 324 | })(); 325 | 326 | //translate CSS 327 | ripCSS(); 328 | 329 | //expose update for re-running respond later on 330 | respond.update = ripCSS; 331 | 332 | //adjust on resize 333 | function callMedia(){ 334 | applyMedia( true ); 335 | } 336 | if( win.addEventListener ){ 337 | win.addEventListener( "resize", callMedia, false ); 338 | } 339 | else if( win.attachEvent ){ 340 | win.attachEvent( "onresize", callMedia ); 341 | } 342 | })(this); 343 | -------------------------------------------------------------------------------- /theme-white/navbar.css: -------------------------------------------------------------------------------- 1 | nav { 2 | height: 60px; 3 | font-family: "Titillium Web", sans-serif; 4 | -webkit-box-shadow: 0px -1px 9px 3px rgba(0,0,0,0.15); 5 | -moz-box-shadow: 0px -1px 9px 3px rgba(0,0,0,0.15); 6 | box-shadow: 0px -1px 9px 3px rgba(0,0,0,0.15); 7 | } 8 | 9 | .navbar a:link, 10 | .navbar a:active, 11 | .navbar a:visited { 12 | color: #ffffff; 13 | text-decoration: none !important; 14 | } 15 | 16 | div#navbar { 17 | padding-bottom: 0; 18 | } 19 | 20 | @media (min-width: 1200px) { 21 | div#navbar { 22 | padding-bottom: 0; 23 | } 24 | } 25 | 26 | 27 | 28 | 29 | .navbar a { 30 | opacity: 1; 31 | transition: all .55s ease-in-out; 32 | -moz-transition: all .55s ease-in-out; 33 | -webkit-transition: all .55s ease-in-out; 34 | } 35 | .navbar a:hover { 36 | opacity: .85; 37 | transition: all 1s ease-in-out; 38 | -moz-transition: all 1s ease-in-out; 39 | -webkit-transition: all 1s ease-in-out; 40 | } 41 | 42 | .navbar-default, 43 | .dropdown-menu { 44 | background-color: rgba(74, 137, 220, 0.9); 45 | border: 0; 46 | } 47 | 48 | .navbar-default .navbar-nav>li>a { 49 | color: #fff; 50 | } 51 | 52 | .navbar-default .navbar-brand:focus, 53 | .navbar-default .navbar-brand:hover { 54 | color: #fff; 55 | } 56 | 57 | .navbar-default .navbar-nav>li>a:focus, 58 | .navbar-default .navbar-nav>li>a:hover { 59 | color: #fff; 60 | background-color: transparent; 61 | } 62 | 63 | .navbar-default .navbar-nav>.open>a, 64 | .navbar-default .navbar-nav>.open>a:focus, 65 | .navbar-default .navbar-nav>.open>a:hover { 66 | color: #fff; 67 | background-color: #4a89dc; 68 | transition: all .35s ease-in-out; 69 | -moz-transition: all .35s ease-in-out; 70 | -webkit-transition: all .35s ease-in-out; 71 | } 72 | 73 | .navbar-brand { 74 | font-size: 30px; 75 | font-style: italic; 76 | margin-top: -2px; 77 | font-weight: 700; 78 | } 79 | 80 | #navbar { 81 | font-weight: 400; 82 | background-color: rgba(74, 137, 220, 0.0) !important; 83 | } 84 | 85 | .navbar { 86 | display: table; 87 | width: 100%; 88 | height: 60px; 89 | } 90 | 91 | .navbar-nav>li>.dropdown-menu.display { 92 | display: block; 93 | } 94 | 95 | nav .container { 96 | display: table-cell; 97 | vertical-align: middle; 98 | } 99 | 100 | .dropdown-menu { 101 | top: 60px; 102 | left: -30px; 103 | box-shadow: none; 104 | transition: all .55s ease-in-out; 105 | -moz-transition: all .55s ease-in-out; 106 | -webkit-transition: all .55s ease-in-out; 107 | } 108 | 109 | .dropdown-menu li { 110 | border-bottom-style: solid; 111 | border-bottom-width: 1px; 112 | border-bottom-color: rgba(204, 204, 204, 0.08); 113 | text-align: center; 114 | transition: all .55s ease-in-out; 115 | -moz-transition: all .55s ease-in-out; 116 | -webkit-transition: all .55s ease-in-out; 117 | } 118 | 119 | .dropdown-menu>li>a { 120 | font-weight: 400; 121 | transition: all .55s ease-in-out; 122 | -moz-transition: all .55s ease-in-out; 123 | -webkit-transition: all .55s ease-in-out; 124 | } 125 | 126 | .dropdown-menu>li>a:hover { 127 | transition: all .55s ease-in-out; 128 | -moz-transition: all .55s ease-in-out; 129 | -webkit-transition: all .55s ease-in-out; 130 | } 131 | 132 | .nav-docs, 133 | .nav-resources { 134 | margin-left: 22px; 135 | } 136 | 137 | .nav-community { 138 | margin-left: 55px; 139 | } 140 | 141 | /* .nav-getstarted { 142 | background-color: rgba(255, 255, 255, 0.0); 143 | border-width: 2px; 144 | border-color: rgb(255, 255, 255); 145 | border-style: solid; 146 | border-radius: 7px; 147 | color: #fff; 148 | width: 154px; 149 | height: 40px; 150 | margin-top: 5px; 151 | margin-left: 15px; 152 | transition: all .55s ease-in-out; 153 | -moz-transition: all .55s ease-in-out; 154 | -webkit-transition: all .55s ease-in-out; 155 | } 156 | */ 157 | 158 | .nav-getstarted:hover { 159 | color: #a0d468; 160 | transition: .5s ease-in-out; 161 | -moz-transition: .5s ease-in-out; 162 | -webkit-transition: .5s ease-in-out; 163 | } 164 | 165 | .navbar-nav { 166 | text-align: center; 167 | font-size: 13px; 168 | } 169 | 170 | @media (min-width: 1200px) { 171 | .navbar-nav { 172 | font-size: 13px; 173 | } 174 | } 175 | 176 | @media (min-width: 1440px) { 177 | .navbar-nav { 178 | font-size: 15px; 179 | } 180 | } 181 | 182 | 183 | 184 | 185 | button a:hover { 186 | text-decoration: none; 187 | } 188 | 189 | button { 190 | opacity: 1; 191 | transition: opacity .55s ease-in-out; 192 | -moz-transition: opacity .55s ease-in-out; 193 | -webkit-transition: opacity .55s ease-in-out; 194 | } 195 | 196 | button:hover { 197 | opacity: .9; 198 | transition: opacity 1s ease-in-out; 199 | -moz-transition: opacity 1s ease-in-out; 200 | -webkit-transition: opacity 1s ease-in-out; 201 | } 202 | 203 | .navbar-default .navbar-nav>.open>a, 204 | .navbar-default .navbar-nav>.open>a:focus, 205 | .navbar-default .navbar-nav>.open>a:hover { 206 | background-color: rgba(74, 137, 220, .0); 207 | border: 0; 208 | } 209 | 210 | .past-main { 211 | background-color: #a0d468; 212 | border: 0; 213 | transition: .5s ease-in-out; 214 | -moz-transition: .5s ease-in-out; 215 | -webkit-transition: .5s ease-in-out; 216 | } 217 | 218 | @media (min-width: 992px) { 219 | ul.nav li.dropdown:hover > ul.dropdown-menu { 220 | display: block; 221 | } 222 | .navbar-nav>li { 223 | padding: 5px 0; 224 | } 225 | .navbar>.container-fluid .navbar-brand, .navbar>.container .navbar-brand { 226 | padding-top: 18px; 227 | } 228 | } 229 | @media (max-width: 991px) { 230 | .nav-docs, .nav-resources { 231 | margin-left: 8px; 232 | } 233 | .nav-community { 234 | margin-left: 0; 235 | } 236 | 237 | .nav-docs, .nav-resources { 238 | margin-left: 0px; 239 | } 240 | 241 | .nav-getstarted { 242 | margin-left: 0; 243 | } 244 | 245 | .dropdown-menu li { 246 | margin-right: 10px; 247 | } 248 | 249 | .navbar-default .navbar-nav .open .dropdown-menu>li>a { 250 | color: #fff; 251 | } 252 | 253 | .nav-getstarted { 254 | margin-left: 0; 255 | } 256 | 257 | .navbar-default .navbar-collapse, .navbar-default .navbar-form { 258 | border-color: rgba(231, 231, 231, 0); 259 | } 260 | 261 | .navbar-default .navbar-toggle .icon-bar { 262 | background-color: #fff; 263 | } 264 | 265 | .navbar-default .navbar-toggle { 266 | border: 0; 267 | } 268 | 269 | .navbar-default .navbar-toggle:focus, .navbar-default .navbar-toggle:hover { 270 | background-color: rgba(221, 221, 221, 0); 271 | } 272 | } 273 | 274 | @media (min-width: 1919px) { 275 | .navbar-nav>li { 276 | padding: 0 20px 1px 0; 277 | font-size: 21px; 278 | } 279 | 280 | a.navbar-brand { 281 | font-size: 33px; 282 | } 283 | 284 | .navbar-default .navbar-nav>li>a { 285 | font-size: 20px; 286 | } 287 | 288 | .nav-getstarted { 289 | font-size: 19px; 290 | width: 200px; 291 | margin-top: 5px; 292 | } 293 | 294 | .dropdown-menu { 295 | top: 56px; 296 | left: -22px; 297 | } 298 | 299 | .navbar>.container-fluid .navbar-brand, .navbar>.container .navbar-brand { 300 | padding-top: 12px; 301 | } 302 | 303 | div#navbar { 304 | width: 1500px; 305 | } 306 | 307 | .dropdown-menu>li>a { 308 | font-size: 18px; 309 | } 310 | 311 | } 312 | 313 | .getstarted { 314 | border: 2px solid #ffffff; 315 | color: #a0d468; 316 | padding: 6px 19px; 317 | border-radius: 6px; 318 | min-width: 260px; 319 | } 320 | .getstarted-container { 321 | margin-top: 17px; 322 | margin-left: 20px; 323 | } 324 | .past-main { 325 | border: 0; 326 | } 327 | @media (max-width: 991px) { 328 | .getstarted-container { 329 | margin-top: 17px; 330 | margin-left: 0; 331 | } 332 | } 333 | 334 | @media (min-width: 1440px) { 335 | .getstarted-container { 336 | margin-top: 13px; 337 | } 338 | } 339 | 340 | @media (min-width: 1919px) { 341 | .getstarted-container { 342 | margin-top: 8px; 343 | margin-left: 20px; 344 | } 345 | } 346 | 347 | @media (min-width: 768px) and (max-width: 1200px) { 348 | .container { 349 | width: 95%; 350 | } 351 | } 352 | 353 | -------------------------------------------------------------------------------- /theme-white/script.js: -------------------------------------------------------------------------------- 1 | (function($) { 2 | var $window = $(window); 3 | var $document = $(document); 4 | 5 | /* 6 | * Scrollspy. 7 | */ 8 | 9 | $document.on('flatdoc:ready', function() { 10 | $("h1, h2, h3, h4, h5").scrollagent(function(cid, pid, currentElement, previousElement) { 11 | if (pid) { 12 | $("[href='#"+pid+"']").removeClass('active'); 13 | } 14 | if (cid) { 15 | $("[href='#"+cid+"']").addClass('active'); 16 | } 17 | }); 18 | }); 19 | 20 | /* 21 | * Anchor jump links. 22 | */ 23 | 24 | $document.on('flatdoc:ready', function() { 25 | $('.menu a').anchorjump({offset: -30}); 26 | }); 27 | 28 | /* 29 | * Title card. 30 | */ 31 | 32 | $(function() { 33 | var $card = $('.title-card'); 34 | if (!$card.length) return; 35 | 36 | var $header = $('.header'); 37 | var headerHeight = $header.length ? $header.outerHeight() : 0; 38 | 39 | $window 40 | .on('resize.title-card', function() { 41 | var windowWidth = $window.width(); 42 | 43 | if (windowWidth < 480) { 44 | $card.css('height', ''); 45 | } else { 46 | var height = $window.height(); 47 | $card.css('height', height - headerHeight); 48 | } 49 | }) 50 | .trigger('resize.title-card'); 51 | }); 52 | 53 | /* 54 | * Sidebar stick. 55 | */ 56 | 57 | $(function() { 58 | var $sidebar = $('.menubar'); 59 | var elTop; 60 | 61 | $window 62 | .on('resize.sidestick', function() { 63 | $sidebar.removeClass('fixed'); 64 | elTop = $sidebar.offset().top; 65 | $window.trigger('scroll.sidestick'); 66 | }) 67 | .on('scroll.sidestick', function() { 68 | var scrollY = $window.scrollTop(); 69 | $sidebar.toggleClass('fixed', (scrollY >= elTop)); 70 | }) 71 | .trigger('resize.sidestick'); 72 | }); 73 | 74 | })(jQuery); 75 | /*! jQuery.scrollagent (c) 2012, Rico Sta. Cruz. MIT License. 76 | * https://github.com/rstacruz/jquery-stuff/tree/master/scrollagent */ 77 | 78 | // Call $(...).scrollagent() with a callback function. 79 | // 80 | // The callback will be called everytime the focus changes. 81 | // 82 | // Example: 83 | // 84 | // $("h2").scrollagent(function(cid, pid, currentElement, previousElement) { 85 | // if (pid) { 86 | // $("[href='#"+pid+"']").removeClass('active'); 87 | // } 88 | // if (cid) { 89 | // $("[href='#"+cid+"']").addClass('active'); 90 | // } 91 | // }); 92 | 93 | (function($) { 94 | 95 | $.fn.scrollagent = function(options, callback) { 96 | // Account for $.scrollspy(function) 97 | if (typeof callback === 'undefined') { 98 | callback = options; 99 | options = {}; 100 | } 101 | 102 | var $sections = $(this); 103 | var $parent = options.parent || $(window); 104 | 105 | // Find the top offsets of each section 106 | var offsets = []; 107 | $sections.each(function(i) { 108 | var offset = $(this).attr('data-anchor-offset') ? 109 | parseInt($(this).attr('data-anchor-offset'), 10) : 110 | (options.offset || 0); 111 | 112 | offsets.push({ 113 | id: $(this).attr('id'), 114 | index: i, 115 | el: this, 116 | offset: offset 117 | }); 118 | }); 119 | 120 | // State 121 | var current = null; 122 | var height = null; 123 | var range = null; 124 | 125 | // Save the height. Do this only whenever the window is resized so we don't 126 | // recalculate often. 127 | $(window).on('resize', function() { 128 | height = $parent.height(); 129 | range = $(document).height(); 130 | }); 131 | 132 | // Find the current active section every scroll tick. 133 | $parent.on('scroll', function() { 134 | var y = $parent.scrollTop(); 135 | y += (height + -800) * (0.3 + 0.7 * Math.pow(y/range, 2)); 136 | 137 | var latest = null; 138 | 139 | for (var i in offsets) { 140 | if (offsets.hasOwnProperty(i)) { 141 | var offset = offsets[i]; 142 | if ($(offset.el).offset().top + offset.offset < y) latest = offset; 143 | } 144 | } 145 | 146 | if (latest && (!current || (latest.index !== current.index))) { 147 | callback.call($sections, 148 | latest ? latest.id : null, 149 | current ? current.id : null, 150 | latest ? latest.el : null, 151 | current ? current.el : null); 152 | current = latest; 153 | } 154 | }); 155 | 156 | $(window).trigger('resize'); 157 | $parent.trigger('scroll'); 158 | 159 | return this; 160 | }; 161 | 162 | })(jQuery); 163 | /*! Anchorjump (c) 2012, Rico Sta. Cruz. MIT License. 164 | * http://github.com/rstacruz/jquery-stuff/tree/master/anchorjump */ 165 | 166 | // Makes anchor jumps happen with smooth scrolling. 167 | // 168 | // $("#menu a").anchorjump(); 169 | // $("#menu a").anchorjump({ offset: -30 }); 170 | // 171 | // // Via delegate: 172 | // $("#menu").anchorjump({ for: 'a', offset: -30 }); 173 | // 174 | // You may specify a parent. This makes it scroll down to the parent. 175 | // Great for tabbed views. 176 | // 177 | // $('#menu a').anchorjump({ parent: '.anchor' }); 178 | // 179 | // You can jump to a given area. 180 | // 181 | // $.anchorjump('#bank-deposit', options); 182 | 183 | (function($) { 184 | var defaults = { 185 | 'speed': 500, 186 | 'offset': 0, 187 | 'for': null, 188 | 'parent': null 189 | }; 190 | 191 | $.fn.anchorjump = function(options) { 192 | options = $.extend({}, defaults, options); 193 | 194 | if (options['for']) { 195 | this.on('click', options['for'], onClick); 196 | } else { 197 | this.on('click', onClick); 198 | } 199 | 200 | function onClick(e) { 201 | var $a = $(e.target).closest('a'); 202 | if (e.ctrlKey || e.metaKey || e.altKey || $a.attr('target')) return; 203 | 204 | e.preventDefault(); 205 | var href = $a.attr('href'); 206 | 207 | $.anchorjump(href, options); 208 | } 209 | }; 210 | 211 | // Jump to a given area. 212 | $.anchorjump = function(href, options) { 213 | options = $.extend({}, defaults, options); 214 | 215 | var top = 0; 216 | 217 | if (href != '#') { 218 | var $area = $(href); 219 | // Find the parent 220 | if (options.parent) { 221 | var $parent = $area.closest(options.parent); 222 | if ($parent.length) { $area = $parent; } 223 | } 224 | if (!$area.length) { return; } 225 | 226 | // Determine the pixel offset; use the default if not available 227 | var offset = 228 | $area.attr('data-anchor-offset') ? 229 | parseInt($area.attr('data-anchor-offset'), 10) : 230 | options.offset; 231 | 232 | top = Math.max(0, $area.offset().top + offset); 233 | } 234 | 235 | $('html, body').animate({ scrollTop: top }, options.speed); 236 | $('body').trigger('anchor', href); 237 | 238 | // Add the location hash via pushState. 239 | if (window.history.pushState) { 240 | window.history.pushState({ href: href }, "", href); 241 | } 242 | }; 243 | })(jQuery); 244 | -------------------------------------------------------------------------------- /theme-white/style.css: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | Please don't edit this file directly. 4 | Instead, edit the stylus (.styl) files and compile it to CSS on your machine. 5 | 6 | */ 7 | /* ---------------------------------------------------------------------------- 8 | * Fonts 9 | */ 10 | @import url("//fonts.googleapis.com/css?family=Montserrat:700|Open+Sans:300"); 11 | /* ---------------------------------------------------------------------------- 12 | * Base 13 | */ 14 | html, 15 | body, 16 | div, 17 | span, 18 | applet, 19 | object, 20 | iframe, 21 | h1, 22 | h2, 23 | h3, 24 | h4, 25 | h5, 26 | h6, 27 | p, 28 | blockquote, 29 | pre, 30 | a, 31 | abbr, 32 | acronym, 33 | address, 34 | big, 35 | cite, 36 | code, 37 | del, 38 | dfn, 39 | em, 40 | img, 41 | ins, 42 | kbd, 43 | q, 44 | s, 45 | samp, 46 | small, 47 | strike, 48 | strong, 49 | sub, 50 | sup, 51 | tt, 52 | var, 53 | dl, 54 | dt, 55 | dd, 56 | ol, 57 | ul, 58 | li, 59 | fieldset, 60 | form, 61 | label, 62 | legend, 63 | table, 64 | caption, 65 | tbody, 66 | tfoot, 67 | thead, 68 | tr, 69 | th, 70 | td { 71 | margin: 0; 72 | padding: 0; 73 | border: 0; 74 | outline: 0; 75 | font-weight: inherit; 76 | font-style: inherit; 77 | font-family: inherit; 78 | font-size: 100%; 79 | vertical-align: baseline; 80 | } 81 | body { 82 | line-height: 1; 83 | color: #000; 84 | background: #fff; 85 | } 86 | ol, 87 | ul { 88 | list-style: none; 89 | } 90 | table { 91 | border-collapse: separate; 92 | border-spacing: 0; 93 | vertical-align: middle; 94 | } 95 | caption, 96 | th, 97 | td { 98 | text-align: left; 99 | font-weight: normal; 100 | vertical-align: middle; 101 | } 102 | a img { 103 | border: 0; 104 | } 105 | img { 106 | border-width: 1px; 107 | border-color: rgba(154, 162, 173, 0.38); 108 | border-style: solid; 109 | /*-webkit-box-shadow: 3px 3px 0px 0px rgba(0,0,0,0.09);*/ 110 | /*-moz-box-shadow: 3px 3px 0px 0px rgba(0,0,0,0.09);*/ 111 | /*box-shadow: 3px 3px 0px 0px rgba(0,0,0,0.09);*/ 112 | /*transition: all 1s ease-in-out;*/ 113 | 114 | } 115 | img:hover { 116 | /*-webkit-box-shadow: 3px 3px 0px 0px rgba(93, 156, 237, 0.2);*/ 117 | /*-moz-box-shadow: 3px 3px 0px 0px rgba(93, 156, 237, 0.2);*/ 118 | /*box-shadow: 3px 3px 0px 0px rgba(93, 156, 237, 0.2);*/ 119 | } 120 | html, 121 | body { 122 | height: 100%; 123 | } 124 | html { 125 | overflow-x: hidden; 126 | } 127 | body, 128 | td, 129 | textarea, 130 | input { 131 | font-family: Helvetica Neue, Open Sans, sans-serif; 132 | line-height: 1.6; 133 | font-size: 13px; 134 | color: #505050; 135 | } 136 | @media (max-width: 480px) { 137 | body, 138 | td, 139 | textarea, 140 | input { 141 | font-size: 12px; 142 | } 143 | } 144 | a { 145 | color: #5c656e; 146 | text-decoration: none; 147 | } 148 | a:hover { 149 | color: #505050; 150 | } 151 | /* ---------------------------------------------------------------------------- 152 | * Content styling 153 | */ 154 | .content p, 155 | .content ul, 156 | .content ol, 157 | .content h1, 158 | .content h2, 159 | .content h3, 160 | .content h4, 161 | .content h5, 162 | .content h6, 163 | .content pre, 164 | .content blockquote { 165 | padding: 10px 0; 166 | -webkit-box-sizing: border-box; 167 | -moz-box-sizing: border-box; 168 | box-sizing: border-box; 169 | font-family: "Titillium Web", Helvetica Neue, Open Sans, sans-serif; 170 | } 171 | .content h1, 172 | .content h2, 173 | .content h3, 174 | .content h4, 175 | .content h5, 176 | .content h6 { 177 | font-weight: bold; 178 | -webkit-font-smoothing: antialiased; 179 | text-rendering: optimizeLegibility; 180 | } 181 | .content pre { 182 | font-family: Menlo, monospace; 183 | } 184 | .content ul > li { 185 | list-style-type: disc; 186 | } 187 | .content ol > li { 188 | list-style-type: decimal; 189 | } 190 | .content ul, 191 | .content ol { 192 | margin-left: 20px; 193 | } 194 | .content ul > li { 195 | list-style-type: none; 196 | position: relative; 197 | } 198 | .content ul > li:before { 199 | content: ''; 200 | display: block; 201 | position: absolute; 202 | left: -17px; 203 | top: 7px; 204 | width: 5px; 205 | height: 5px; 206 | -webkit-border-radius: 4px; 207 | border-radius: 4px; 208 | -webkit-box-sizing: border-box; 209 | -moz-box-sizing: border-box; 210 | box-sizing: border-box; 211 | background: #fff; 212 | border: solid 1px #9090aa; 213 | } 214 | .content li > :first-child { 215 | padding-top: 0; 216 | } 217 | .content strong, 218 | .content b { 219 | font-weight: bold; 220 | } 221 | .content i, 222 | .content em { 223 | font-style: italic; 224 | color: #9090aa; 225 | } 226 | .content code { 227 | font-family: Menlo, monospace; 228 | background: #f3f6fb; 229 | padding: 1px 3px; 230 | font-size: 1em; 231 | } 232 | .content pre > code { 233 | display: block; 234 | background: transparent; 235 | font-size: 1em; 236 | letter-spacing: -1px; 237 | border: solid 1px #e7eaee; 238 | border-top: solid 1px #dbdde2; 239 | border-left: solid 1px #e2e5e9; 240 | padding: 15px; 241 | background-color: #f3f6fb; 242 | border-radius: 2px; 243 | } 244 | .content blockquote :first-child { 245 | padding-top: 0; 246 | } 247 | .content blockquote :last-child { 248 | padding-bottom: 0; 249 | } 250 | .content table { 251 | margin-top: 10px; 252 | margin-bottom: 10px; 253 | padding: 0; 254 | border-collapse: collapse; 255 | clear: both; 256 | float: left; 257 | } 258 | .content table tr { 259 | border-top: 1px solid #ccc; 260 | background-color: #fff; 261 | margin: 0; 262 | padding: 0; 263 | } 264 | .content table tr :nth-child(2n) { 265 | background-color: #f8f8f8; 266 | } 267 | .content table tr th { 268 | text-align: auto; 269 | font-weight: bold; 270 | border: 1px solid #ccc; 271 | margin: 0; 272 | padding: 6px 13px; 273 | } 274 | .content table tr td { 275 | text-align: auto; 276 | border: 1px solid #ccc; 277 | margin: 0; 278 | padding: 6px 13px; 279 | } 280 | .content table tr th :first-child, 281 | .content table tr td :first-child { 282 | margin-top: 0; 283 | } 284 | .content table tr th :last-child, 285 | .content table tr td :last-child { 286 | margin-bottom: 0; 287 | } 288 | .content a:link, 289 | .content a:active, 290 | .content a:visited { 291 | color: #5d9cec; 292 | } 293 | /* ---------------------------------------------------------------------------- 294 | * Content 295 | */ 296 | .content-root { 297 | min-height: 90%; 298 | position: relative; 299 | } 300 | .content { 301 | padding-top: 0px; 302 | padding-bottom: 40px; 303 | padding-left: 40px; 304 | padding-right: 40px; 305 | zoom: 1; 306 | max-width: 700px; 307 | } 308 | .content:before, 309 | .content:after { 310 | content: ""; 311 | display: table; 312 | } 313 | .content:after { 314 | clear: both; 315 | } 316 | .content blockquote { 317 | color: #9090aa; 318 | /* text-shadow: 0 1px 0 rgba(255,255,255,0.5); */ 319 | } 320 | .content h1, 321 | .content h2, 322 | .content h3 { 323 | -webkit-font-smoothing: antialiased; 324 | text-rendering: optimizeLegibility; 325 | font-family: "Titillium Web"; 326 | font-weight: 100; 327 | padding-bottom: 0; 328 | text-transform: none; 329 | } 330 | .content h1 + p, 331 | .content h2 + p, 332 | .content h3 + p, 333 | .content h1 ul, 334 | .content h2 ul, 335 | .content h3 ul, 336 | .content h1 ol, 337 | .content h2 ol, 338 | .content h3 ol { 339 | padding-top: 10px; 340 | } 341 | .content h1, 342 | .content h2 { 343 | /* text-transform: uppercase; 344 | letter-spacing: 1px; */ 345 | font-size: 2em; 346 | } 347 | .content h3 { 348 | font-size: 1.6em !important; 349 | } 350 | .content h4, 351 | .content h5 { 352 | font-size: 1.2em !important; 353 | font-weight: 400; 354 | } 355 | .content h6 { 356 | font-weight: 100 !important; 357 | font-size: 19px; 358 | margin-bottom: -18px; 359 | color: #8493a8; 360 | } 361 | .content p { 362 | font-family: "Titillium Web"; 363 | } 364 | img { 365 | max-width: 100%; 366 | } 367 | .content h1, 368 | .content h2, 369 | .content .big-heading, 370 | body.big-h3 .content h3 { 371 | padding-top: 80px; 372 | } 373 | .content h1:before, 374 | .content h2:before, 375 | .content .big-heading:before, 376 | body.big-h3 .content h3:before { 377 | display: block; 378 | content: ''; 379 | background: -webkit-linear-gradient(left, #dfe2e7 80%, rgba(223,226,231,0)); 380 | background: -moz-linear-gradient(left, #dfe2e7 80%, rgba(223,226,231,0)); 381 | background: -o-linear-gradient(left, #dfe2e7 80%, rgba(223,226,231,0)); 382 | background: -ms-linear-gradient(left, #dfe2e7 80%, rgba(223,226,231,0)); 383 | background: linear-gradient(to right, #dfe2e7 80%, rgba(223,226,231,0)); 384 | -webkit-box-shadow: 0 1px 0 rgba(255,255,255,0.4); 385 | box-shadow: 0 1px 0 rgba(255,255,255,0.4); 386 | height: 1px; 387 | position: relative; 388 | top: -40px; 389 | left: -40px; 390 | width: 100%; 391 | } 392 | @media (max-width: 768px) { 393 | .content h1, 394 | .content h2, 395 | .content .big-heading, 396 | body.big-h3 .content h3 { 397 | padding-top: 40px; 398 | } 399 | .content h1:before, 400 | .content h2:before, 401 | .content .big-heading:before, 402 | body.big-h3 .content h3:before { 403 | background: #dfe2e7; 404 | left: -40px; 405 | top: -20px; 406 | width: 120%; 407 | } 408 | img { 409 | max-width: 90%; 410 | } 411 | } 412 | .content h4, 413 | .content h5, 414 | .content .small-heading, 415 | body:not(.big-h3) .content h3 { 416 | border-bottom: solid 1px rgba(0,0,0,0.07); 417 | color: #626277; 418 | padding-top: 30px; 419 | padding-bottom: 10px; 420 | } 421 | body:not(.big-h3) .content h3 { 422 | font-size: 0.9em; 423 | } 424 | .content h1:first-child { 425 | padding-top: 0; 426 | } 427 | .content h1:first-child, 428 | .content h1:first-child a, 429 | .content h1:first-child a:visited { 430 | color: #505050; 431 | } 432 | .content h1:first-child:before { 433 | display: none; 434 | } 435 | @media (max-width: 768px) { 436 | .content h4, 437 | .content h5, 438 | .content .small-heading, 439 | body:not(.big-h3) .content h3 { 440 | padding-top: 20px; 441 | } 442 | } 443 | @media (max-width: 480px) { 444 | .content { 445 | padding: 20px; 446 | padding-top: 40px; 447 | } 448 | .content h4, 449 | .content h5, 450 | .content .small-heading, 451 | body:not(.big-h3) .content h3 { 452 | padding-top: 10px; 453 | } 454 | } 455 | body.no-literate .content pre > code { 456 | background: #f3f6fb; 457 | border: solid 1px #e7eaee; 458 | border-top: solid 1px #dbdde2; 459 | border-left: solid 1px #e2e5e9; 460 | display: block; 461 | padding: 10px; 462 | -webkit-border-radius: 2px; 463 | border-radius: 2px; 464 | overflow: auto; 465 | } 466 | body.no-literate .content pre > code { 467 | -webkit-overflow-scrolling: touch; 468 | } 469 | body.no-literate .content pre > code::-webkit-scrollbar { 470 | width: 15px; 471 | height: 15px; 472 | } 473 | body.no-literate .content pre > code::-webkit-scrollbar-thumb { 474 | background: #ddd; 475 | -webkit-border-radius: 8px; 476 | border-radius: 8px; 477 | border: solid 4px #f3f6fb; 478 | } 479 | body.no-literate .content pre > code:hover::-webkit-scrollbar-thumb { 480 | background: #999; 481 | -webkit-box-shadow: inset 2px 2px 3px rgba(0,0,0,0.2); 482 | box-shadow: inset 2px 2px 3px rgba(0,0,0,0.2); 483 | } 484 | @media (max-width: 1180px) { 485 | .content pre > code { 486 | background: #f3f6fb; 487 | border: solid 1px #e7eaee; 488 | border-top: solid 1px #dbdde2; 489 | border-left: solid 1px #e2e5e9; 490 | display: block; 491 | padding: 10px; 492 | -webkit-border-radius: 2px; 493 | border-radius: 2px; 494 | overflow: auto; 495 | } 496 | .content pre > code { 497 | -webkit-overflow-scrolling: touch; 498 | } 499 | .content pre > code::-webkit-scrollbar { 500 | width: 15px; 501 | height: 15px; 502 | } 503 | .content pre > code::-webkit-scrollbar-thumb { 504 | background: #ddd; 505 | -webkit-border-radius: 8px; 506 | border-radius: 8px; 507 | border: solid 4px #f3f6fb; 508 | } 509 | .content pre > code:hover::-webkit-scrollbar-thumb { 510 | background: #999; 511 | -webkit-box-shadow: inset 2px 2px 3px rgba(0,0,0,0.2); 512 | box-shadow: inset 2px 2px 3px rgba(0,0,0,0.2); 513 | } 514 | } 515 | .button { 516 | -webkit-font-smoothing: antialiased; 517 | text-rendering: optimizeLegibility; 518 | font-family: montserrat, sans-serif; 519 | letter-spacing: -1px; 520 | font-weight: bold; 521 | display: inline-block; 522 | padding: 3px 25px; 523 | border: solid 2px #2badad; 524 | -webkit-border-radius: 20px; 525 | border-radius: 20px; 526 | margin-right: 15px; 527 | } 528 | .button, 529 | .button:visited { 530 | background: #2badad; 531 | color: #fff; 532 | text-shadow: none; 533 | } 534 | .button:hover { 535 | border-color: #111; 536 | background: #111; 537 | color: #fff; 538 | } 539 | .button.light, 540 | .button.light:visited { 541 | background: transparent; 542 | color: #9090aa; 543 | border-color: #9090aa; 544 | text-shadow: none; 545 | } 546 | .button.light:hover { 547 | border-color: #9090aa; 548 | background: #9090aa; 549 | color: #fff; 550 | } 551 | .content .button + em { 552 | color: #9090aa; 553 | } 554 | /* Custom */ 555 | div.toggle-menu { 556 | background: url("img/expand.png") no-repeat; 557 | height: 8px; 558 | width: 6px; 559 | float: left; 560 | margin: 8px 0 0 -12px; 561 | opacity: .4; 562 | cursor: pointer; 563 | } 564 | div.expand { 565 | background: url("img/toggle.png") no-repeat; 566 | } 567 | @media (min-width: 1180px) { 568 | /* body:not(.no-literate) .content-root { 569 | background-color: #f3f6fb; 570 | -webkit-box-shadow: inset 780px 0 #fff, inset 781px 0 #dfe2e7, inset 790px 0 5px -10px rgba(0,0,0,0.1); 571 | box-shadow: inset 780px 0 #fff, inset 781px 0 #dfe2e7, inset 790px 0 5px -10px rgba(0,0,0,0.1); 572 | } */ 573 | } 574 | @media (min-width: 1180px) { 575 | body:not(.no-literate) .content { 576 | padding-right: 0; 577 | padding-bottom: 300px; 578 | width: 930px; 579 | max-width: none; 580 | } 581 | body:not(.no-literate) .content > p, 582 | body:not(.no-literate) .content > ul, 583 | body:not(.no-literate) .content > ol, 584 | body:not(.no-literate) .content > h1, 585 | body:not(.no-literate) .content > h2, 586 | body:not(.no-literate) .content > h3, 587 | body:not(.no-literate) .content > h4, 588 | body:not(.no-literate) .content > h5, 589 | body:not(.no-literate) .content > h6, 590 | body:not(.no-literate) .content > pre, 591 | body:not(.no-literate) .content > blockquote { 592 | width: 900px; 593 | -webkit-box-sizing: border-box; 594 | -moz-box-sizing: border-box; 595 | box-sizing: border-box; 596 | padding-right: 40px; 597 | padding-left: 40px; 598 | } 599 | body:not(.no-literate) .content > h1, 600 | body:not(.no-literate) .content > h2, 601 | body:not(.no-literate) .content > h3 { 602 | clear: both; 603 | width: 100%; 604 | } 605 | body:not(.no-literate) .content > pre, 606 | body:not(.no-literate) .content > blockquote { 607 | width: 780px; 608 | padding-left: 75px; 609 | padding-right: 20px; 610 | float: left; 611 | clear: right; 612 | } 613 | body:not(.no-literate) .content > pre + p, 614 | body:not(.no-literate) .content > blockquote + p, 615 | body:not(.no-literate) .content > pre + ul, 616 | body:not(.no-literate) .content > blockquote + ul, 617 | body:not(.no-literate) .content > pre + ol, 618 | body:not(.no-literate) .content > blockquote + ol, 619 | body:not(.no-literate) .content > pre + h4, 620 | body:not(.no-literate) .content > blockquote + h4, 621 | body:not(.no-literate) .content > pre + h5, 622 | body:not(.no-literate) .content > blockquote + h5, 623 | body:not(.no-literate) .content > pre + h6, 624 | body:not(.no-literate) .content > blockquote + h6 { 625 | clear: both; 626 | } 627 | body:not(.no-literate) .content > p, 628 | body:not(.no-literate) .content > ul, 629 | body:not(.no-literate) .content > ol, 630 | body:not(.no-literate) .content > h4, 631 | body:not(.no-literate) .content > h5, 632 | body:not(.no-literate) .content > h6 { 633 | float: left; 634 | clear: left; 635 | } 636 | body:not(.no-literate) .content > h4, 637 | body:not(.no-literate) .content > h5, 638 | body:not(.no-literate) .content > .small-heading, 639 | body:not(.big-h3) body:not(.no-literate) .content > h3 { 640 | margin-left: 40px; 641 | width: 720px; 642 | margin-bottom: 3px; 643 | padding-left: 0; 644 | padding-right: 0; 645 | } 646 | body:not(.no-literate) .content > table { 647 | margin-left: 40px; 648 | margin-right: 40px; 649 | max-width: 720px; 650 | } 651 | body:not(.no-literate):not(.big-h3) .content > h3 { 652 | margin-left: 40px; 653 | width: 720px; 654 | margin-bottom: 3px; 655 | padding-left: 0; 656 | padding-right: 0; 657 | } 658 | } 659 | h1#introduction { 660 | padding-top: 30px; 661 | } 662 | .header { 663 | background: #434a54; 664 | /* text-shadow: 0 1px 0 rgba(255,255,255,0.5); */ 665 | border-bottom: solid 1px #dfe2e7; 666 | padding: 15px 15px 15px 30px; 667 | zoom: 1; 668 | line-height: 20px; 669 | position: fixed; 670 | width: 100%; 671 | z-index: 999; 672 | } 673 | .header:before, 674 | .header:after { 675 | content: ""; 676 | display: table; 677 | } 678 | .header:after { 679 | clear: both; 680 | } 681 | .header .left { 682 | float: left; 683 | } 684 | .header .right { 685 | text-align: right; 686 | position: absolute; 687 | right: 15px; 688 | top: 15px; 689 | } 690 | .header .right iframe { 691 | display: inline-block; 692 | vertical-align: middle; 693 | } 694 | .header h1 { 695 | -webkit-font-smoothing: antialiased; 696 | text-rendering: optimizeLegibility; 697 | font-weight: bold; 698 | font-style: italic; 699 | font-family: "Titillium Web", montserrat, sans-serif; 700 | font-size: 28px; 701 | } 702 | .header h1, 703 | .header h1 a, 704 | .header h1 a:visited { 705 | color: #fff; 706 | } 707 | .header h1 a:hover { 708 | color: #fff; 709 | } 710 | .header li a { 711 | font-size: 0.88em; 712 | color: #fff; 713 | display: block; 714 | } 715 | .header li a:hover { 716 | color: #fff; 717 | } 718 | @media (min-width: 480px) { 719 | .header h1 { 720 | float: left; 721 | } 722 | .header ul, 723 | .header li { 724 | display: block; 725 | float: left; 726 | } 727 | .header ul { 728 | margin-left: -15px; 729 | } 730 | .header h1 + ul { 731 | border-left: solid 1px #dfe2e7; 732 | margin-left: 15px; 733 | } 734 | .header li { 735 | border-left: solid 1px rgba(255,255,255,0.5); 736 | border-right: solid 1px #dfe2e7; 737 | } 738 | .header li:last-child { 739 | border-right: 0; 740 | } 741 | .header li a { 742 | padding: 0 15px; 743 | } 744 | } 745 | @media (max-width: 480px) { 746 | .right { 747 | display: none; 748 | } 749 | } 750 | .menubar { 751 | -webkit-font-smoothing: antialiased; 752 | text-rendering: optimizeLegibility; 753 | } 754 | .menubar .section { 755 | padding: 30px 30px; 756 | -webkit-box-sizing: border-box; 757 | -moz-box-sizing: border-box; 758 | box-sizing: border-box; 759 | } 760 | .menubar .section + .section { 761 | border-top: solid 1px #dfe2e7; 762 | } 763 | .menubar .section.no-line { 764 | border-top: 0; 765 | padding-top: 0; 766 | } 767 | a.big.button { 768 | display: block; 769 | -webkit-box-sizing: border-box; 770 | -moz-box-sizing: border-box; 771 | box-sizing: border-box; 772 | width: 100%; 773 | padding: 10px 20px; 774 | text-align: center; 775 | font-weight: bold; 776 | font-size: 1.1em; 777 | background: transparent; 778 | border: solid 3px #2badad; 779 | -webkit-border-radius: 30px; 780 | border-radius: 30px; 781 | font-family: montserrat, sans-serif; 782 | } 783 | a.big.button, 784 | a.big.button:visited { 785 | color: #2badad; 786 | text-decoration: none; 787 | } 788 | a.big.button:hover { 789 | background: #2badad; 790 | } 791 | a.big.button:hover, 792 | a.big.button:hover:visited { 793 | color: #fff; 794 | } 795 | @media (max-width: 480px) { 796 | .menubar { 797 | padding: 20px; 798 | border-bottom: solid 1px #dfe2e7; 799 | } 800 | } 801 | @media (max-width: 768px) { 802 | /* .menubar { 803 | display: none; 804 | } */ 805 | ul.level-1 { 806 | margin-top: 45px; 807 | } 808 | } 809 | @media (min-width: 768px) { 810 | .content-root { 811 | padding-left: 270px; 812 | padding-top: 45px; 813 | } 814 | .menubar { 815 | position: absolute; 816 | left: 0; 817 | top: 0; 818 | bottom: 0; 819 | width: 270px; 820 | border-right: solid 1px #dfe2e7; 821 | padding-top: 45px; 822 | } 823 | .menubar.fixed { 824 | position: fixed; 825 | overflow-y: auto; 826 | } 827 | .menubar.fixed { 828 | -webkit-overflow-scrolling: touch; 829 | } 830 | .menubar.fixed::-webkit-scrollbar { 831 | width: 15px; 832 | height: 15px; 833 | } 834 | .menubar.fixed::-webkit-scrollbar-thumb { 835 | background: #ddd; 836 | -webkit-border-radius: 8px; 837 | border-radius: 8px; 838 | border: solid 4px #fff; 839 | } 840 | .menubar.fixed:hover::-webkit-scrollbar-thumb { 841 | background: #999; 842 | -webkit-box-shadow: inset 2px 2px 3px rgba(0,0,0,0.2); 843 | box-shadow: inset 2px 2px 3px rgba(0,0,0,0.2); 844 | } 845 | } 846 | .menubar { 847 | font-size: 0.9em; 848 | } 849 | .menu ul.level-1 > li + li { 850 | margin-top: 8px; 851 | } 852 | .menu a { 853 | -webkit-box-sizing: border-box; 854 | -moz-box-sizing: border-box; 855 | box-sizing: border-box; 856 | position: relative; 857 | display: block; 858 | padding-top: 1px; 859 | padding-bottom: 1px; 860 | margin-right: -30px; 861 | } 862 | .menu a, 863 | .menu a:visited { 864 | color: #5C656E; 865 | } 866 | .menu a:hover { 867 | color: #33373E; 868 | } 869 | .menu a.level-1 { 870 | font-family: "Titillium Web", montserrat, sans-serif; 871 | font-size: 14px; 872 | font-weight: 600; 873 | } 874 | .menu a.level-1, 875 | .menu a.level-1:visited { 876 | color: #626277; 877 | } 878 | .menu a.level-1:hover { 879 | color: #707083; 880 | } 881 | .menu a.level-2 { 882 | font-weight: 600; 883 | font-size: 12px; 884 | padding-left: 4px; 885 | color: #7a7b7c; 886 | font-family: "Titillium Web", sans-serif; 887 | } 888 | .menu a.level-2:hover { 889 | color: #4c4d4e; 890 | } 891 | .menu a.level-3 { 892 | font-weight: normal; 893 | font-size: 11px; 894 | padding-left: 10px; 895 | color: #5e5e5e; 896 | font-family: "Titillium Web", sans-serif; 897 | } 898 | .menu a.level-3:hover { 899 | color: #444444; 900 | } 901 | .menu a.level-4 { 902 | font-weight: normal; 903 | font-size: 0.9em; 904 | padding-left: 16px; 905 | color: #7c7d7d; 906 | font-family: "Titillium Web", sans-serif; 907 | } 908 | .menu a.level-4:hover { 909 | color: #484949; 910 | } 911 | .menu a.level-5 { 912 | font-weight: normal; 913 | font-size: 0.9em; 914 | padding-left: 22px; 915 | color: #9d9d9d; 916 | font-family: "Titillium Web", sans-serif; 917 | } 918 | .menu a.level-5:hover { 919 | color: #8f8f8f; 920 | } 921 | .menu a.active { 922 | font-weight: bold !important; 923 | } 924 | .menu a.active, 925 | .menu a.active:visited, 926 | .menu a.active:hover { 927 | color: #5983bd !important; 928 | } 929 | .menu a.active:after { 930 | /* content: ''; */ 931 | display: block; 932 | -webkit-box-sizing: border-box; 933 | -moz-box-sizing: border-box; 934 | box-sizing: border-box; 935 | position: absolute; 936 | top: 8px; 937 | right: 30px; 938 | width: 9px; 939 | height: 3px; 940 | -webkit-border-radius: 2px; 941 | border-radius: 2px; 942 | background: #5983bd; 943 | } 944 | code .string, 945 | code .number { 946 | color: #3ac; 947 | } 948 | code .init { 949 | color: #383; 950 | } 951 | code .keyword { 952 | font-weight: bold; 953 | } 954 | code .comment { 955 | color: #adadcc; 956 | } 957 | .large-brief .content > h1:first-child + p, 958 | .content > p.brief { 959 | font-size: 1.3em; 960 | font-family: Open Sans, sans-serif; 961 | font-weight: 300; 962 | } 963 | .title-area { 964 | min-height: 100px; 965 | -webkit-box-sizing: border-box; 966 | -moz-box-sizing: border-box; 967 | box-sizing: border-box; 968 | -webkit-font-smoothing: antialiased; 969 | text-rendering: optimizeLegibility; 970 | text-align: center; 971 | border-bottom: solid 1px #dfe2e7; 972 | overflow: hidden; 973 | } 974 | .title-area > img.bg { 975 | z-index: 0; 976 | position: absolute; 977 | left: -9999px; 978 | } 979 | .title-area > div { 980 | position: relative; 981 | z-index: 1; 982 | } 983 | li#getting-started-item::before { 984 | content: ''; 985 | top: 10px; 986 | right: 30px; 987 | } 988 | img.noborder { 989 | border: 0 !important; 990 | box-shadow: 0px 0px 0px 0px; 991 | } 992 | 993 | /* Edits */ 994 | 995 | table.widgets-table td img { 996 | padding: 10px; 997 | } 998 | 999 | .content table tr :nth-child(2n) { 1000 | background-color: #ffffff; 1001 | } 1002 | 1003 | .no-border { 1004 | border-style: none; 1005 | box-shadow: 0px 0px 0px 0px; 1006 | } -------------------------------------------------------------------------------- /theme-white/style.styl: -------------------------------------------------------------------------------- 1 | support-for-ie = true 2 | 3 | @import 'nib' 4 | 5 | // Fonts 6 | $body-font = Helvetica Neue, Open Sans, sans-serif 7 | $mono-font = Menlo, monospace 8 | 9 | // Margins 10 | $pad = 40px // Space between things 11 | $sidepad = 30px // Padding to the left of the sidebar 12 | $minipad = 20px // Space for mobile 13 | $vmargin = 10px // Margin between blocks 14 | 15 | // Colors 16 | $offwhite = #f3f6fb 17 | $grey = #9090aa 18 | $txt = #505050 19 | $accent = #3cc * 0.85 20 | $line = #e4e7ec * 0.98 21 | 22 | // Misc 23 | $shadow-str = 0.1 24 | 25 | // Dimensions 26 | $sidebar-width = 230px 27 | $content-width = 550px 28 | $pre-width = 380px 29 | 30 | /* ---------------------------------------------------------------------------- 31 | * Fonts 32 | */ 33 | 34 | @import url('//fonts.googleapis.com/css?family=Montserrat:700|Open+Sans:300') 35 | 36 | // ---------------------------------------------------------------------------- 37 | // Mixins 38 | 39 | scrollbar($bg=white) 40 | & 41 | -webkit-overflow-scrolling: touch 42 | &::-webkit-scrollbar 43 | width: 15px 44 | height: 15px 45 | &::-webkit-scrollbar-thumb 46 | background: #ddd 47 | border-radius: 8px 48 | border: solid 4px $bg 49 | &:hover::-webkit-scrollbar-thumb 50 | background: #999 51 | box-shadow: inset 2px 2px 3px rgba(0, 0, 0, 0.2) 52 | 53 | antialias() 54 | -webkit-font-smoothing: antialiased 55 | text-rendering: optimizeLegibility 56 | 57 | /* ---------------------------------------------------------------------------- 58 | * Base 59 | */ 60 | 61 | global-reset() 62 | 63 | html, body 64 | height: 100% 65 | 66 | html 67 | overflow-x: hidden 68 | 69 | body, td, textarea, input 70 | font-family: $body-font 71 | line-height: 1.6 72 | font-size: 13px 73 | color:$txt 74 | 75 | @media (max-width: 480px) /* Mobile */ 76 | font-size: 12px 77 | 78 | a 79 | color: $accent 80 | text-decoration: none 81 | &:hover 82 | color: $accent * 0.8 83 | 84 | /* ---------------------------------------------------------------------------- 85 | * Content styling 86 | */ 87 | 88 | .content 89 | p, ul, ol, h1, h2, h3, h4, h5, h6, pre, blockquote 90 | padding: $vmargin 0 91 | box-sizing: border-box 92 | 93 | h1, h2, h3, h4, h5, h6 94 | font-weight: bold 95 | antialias() 96 | 97 | pre 98 | font-family: $mono-font 99 | 100 | ul > li 101 | list-style-type: disc 102 | 103 | ol > li 104 | list-style-type: decimal 105 | 106 | ul, ol 107 | margin-left: 20px 108 | 109 | ul > li 110 | list-style-type: none 111 | position: relative 112 | &:before 113 | content: '' 114 | display: block 115 | absolute: left -17px top 7px 116 | width: 5px 117 | height: 5px 118 | border-radius: 4px 119 | box-sizing: border-box 120 | background: white 121 | border: solid 1px $grey 122 | 123 | li > :first-child 124 | padding-top: 0 125 | 126 | strong, b 127 | font-weight: bold 128 | 129 | i, em 130 | font-style: italic 131 | color: $grey 132 | 133 | code 134 | font-family: $mono-font 135 | background: $offwhite 136 | padding: 1px 3px 137 | font-size: 0.95em 138 | 139 | pre > code 140 | display: block 141 | background: transparent 142 | font-size: 0.85em 143 | letter-spacing: -1px 144 | 145 | blockquote 146 | :first-child 147 | padding-top: 0 148 | :last-child 149 | padding-bottom: 0 150 | 151 | table 152 | 153 | margin-top: $vmargin 154 | margin-bottom: $vmargin 155 | padding: 0 156 | border-collapse: collapse 157 | clear: both 158 | float: left 159 | 160 | tr 161 | border-top: 1px solid #cccccc 162 | background-color: white 163 | margin: 0 164 | padding: 0 165 | 166 | :nth-child(2n) 167 | background-color: #f8f8f8 168 | 169 | th 170 | text-align: auto; 171 | font-weight: bold 172 | border: 1px solid #cccccc 173 | margin: 0 174 | padding: 6px 13px 175 | 176 | td 177 | text-align: auto; 178 | border: 1px solid #cccccc 179 | margin: 0 180 | padding: 6px 13px 181 | 182 | th, td 183 | :first-child 184 | 185 | margin-top: 0; 186 | :last-child 187 | margin-bottom: 0; 188 | 189 | 190 | 191 | 192 | 193 | /* ---------------------------------------------------------------------------- 194 | * Content 195 | */ 196 | 197 | .content-root 198 | min-height: 90% 199 | position: relative 200 | 201 | .content 202 | padding-top: $pad - $vmargin 203 | padding-bottom: $pad 204 | padding-left: $pad 205 | padding-right: $pad 206 | clearfix() 207 | 208 | max-width: 700px 209 | 210 | blockquote 211 | color: $grey 212 | text-shadow: 0 1px 0 rgba(white, 0.5) 213 | 214 | h1, h2, h3 215 | antialias() 216 | font-family: montserrat 217 | padding-bottom: 0 218 | 219 | + p, ul, ol 220 | padding-top: 10px 221 | 222 | h1, h2 223 | text-transform: uppercase 224 | letter-spacing: 1px 225 | font-size: 1.5em 226 | 227 | h3 228 | font-size: 1.2em 229 | 230 | // Lines 231 | h1, h2, .big-heading 232 | padding-top: $pad * 2 233 | &:before 234 | display: block 235 | content: '' 236 | background: linear-gradient(left, rgba($line, 1.0) 80%, rgba($line, 0.0)) 237 | box-shadow: 0 1px 0 rgba(white, 0.4) 238 | height: 1px 239 | position: relative 240 | top: $pad * -1 241 | left: $pad * -1 242 | width: 100% 243 | 244 | @media (max-width: 768px) /* Mobile and tablet */ 245 | padding-top: $minipad * 2 246 | &:before 247 | background: $line 248 | left: $pad * -1 249 | top: $minipad * -1 250 | width: 120% 251 | 252 | // Small headings 253 | h4, h5, .small-heading 254 | border-bottom: solid 1px rgba(black, 0.07) 255 | color: $grey 256 | padding-top: $vmargin * 3 257 | padding-bottom: 10px 258 | 259 | body:not(.big-h3) & h3 260 | @extends .content .small-heading 261 | font-size: 0.9em 262 | 263 | body.big-h3 & h3 264 | @extends .content .big-heading 265 | 266 | h1:first-child 267 | padding-top: 0 268 | &, a, a:visited 269 | color: $txt 270 | &:before 271 | display: none 272 | 273 | @media (max-width: 768px) /* Tablet */ 274 | .content 275 | h4, h5, .small-heading, body:not(.big-h3) & h3 276 | padding-top: $vmargin * 2 277 | 278 | @media (max-width: 480px) /* Mobile */ 279 | .content 280 | padding: $minipad 281 | padding-top: $minipad * 2 282 | 283 | h4, h5, .small-heading, body:not(.big-h3) & h3 284 | padding-top: $vmargin 285 | 286 | // ---------------------------------------------------------------------------- 287 | // Code blocks 288 | 289 | inset-box() 290 | background: $offwhite 291 | border: solid 1px $offwhite*0.95 292 | border-top: solid 1px $offwhite*0.9 293 | border-left: solid 1px $offwhite*0.93 294 | display: block 295 | padding: 10px 296 | border-radius: 2px 297 | 298 | overflow: auto 299 | scrollbar($offwhite) 300 | 301 | body.no-literate .content pre > code 302 | inset-box() 303 | 304 | @media (max-width: 1180px) /* Small desktop */ 305 | .content pre > code 306 | inset-box() 307 | 308 | // ---------------------------------------------------------------------------- 309 | // Buttons 310 | 311 | .button 312 | antialias() 313 | font-family: montserrat, sans-serif 314 | letter-spacing: -1px 315 | font-weight: bold 316 | 317 | display: inline-block 318 | padding: 3px 25px 319 | 320 | border: solid 2px $accent 321 | border-radius: 20px 322 | 323 | margin-right: 15px 324 | 325 | &, &:visited 326 | background: $accent 327 | color: white 328 | text-shadow: none 329 | 330 | &:hover 331 | border-color: #111 332 | background: #111 333 | color: white 334 | 335 | &.light 336 | &, &:visited 337 | background: transparent 338 | color: $grey 339 | border-color: $grey 340 | text-shadow: none 341 | 342 | &:hover 343 | border-color: $grey 344 | background: $grey 345 | color: white 346 | 347 | .content 348 | .button + em 349 | color: $grey 350 | 351 | 352 | // ---------------------------------------------------------------------------- 353 | // Literate mode content 354 | 355 | @media (min-width: 1180px) /* Big desktop */ 356 | body:not(.no-literate) 357 | .content-root 358 | background-color: $offwhite 359 | $w = ($sidebar-width + $content-width) 360 | box-shadow: inset $w 0 white, inset ($w + 1) 0 $line, inset ($w + 10) 0 5px -10px rgba(black, $shadow-str) 361 | 362 | // Literate mode 363 | @media (min-width: 1180px) /* Big desktop */ 364 | small-heading() 365 | margin-left: $pad 366 | width: $content-width - $pad * 2 367 | margin-bottom: 3px 368 | 369 | padding-left: 0 370 | padding-right: 0 371 | 372 | body:not(.no-literate) 373 | .content 374 | padding-left: 0 375 | padding-right: 0 376 | 377 | width: $content-width + $pre-width 378 | max-width: none 379 | 380 | > 381 | p, ul, ol, h1, h2, h3, h4, h5, h6, pre, blockquote 382 | width: $content-width 383 | box-sizing: border-box 384 | padding-right: $pad 385 | padding-left: $pad 386 | h1, h2, h3 387 | clear: both 388 | width: 100% 389 | pre, blockquote 390 | width: $pre-width 391 | padding-left: ($pad/2) 392 | padding-right: ($pad/2) 393 | float: right 394 | clear: right 395 | + 396 | p, ul, ol, h4, h5, h6 397 | clear: both 398 | p, ul, ol, h4, h5, h6 399 | float: left 400 | clear: left 401 | 402 | h4, h5, .small-heading, body:not(.big-h3) & h3 403 | small-heading() 404 | 405 | table 406 | margin-left: $pad 407 | margin-right: $pad 408 | max-width: $content-width - $pad*2 409 | 410 | body:not(.no-literate):not(.big-h3) 411 | .content > h3 412 | small-heading() 413 | 414 | // ---------------------------------------------------------------------------- 415 | // Header 416 | 417 | .header 418 | background: $offwhite 419 | text-shadow: 0 1px 0 rgba(white, 0.5) 420 | border-bottom: solid 1px $line 421 | padding: 15px 15px 15px $sidepad 422 | clearfix() 423 | 424 | line-height: 20px 425 | position: relative 426 | 427 | .left 428 | float: left 429 | 430 | .right 431 | text-align: right 432 | position: absolute 433 | right: 15px 434 | top: 15px 435 | 436 | iframe 437 | display: inline-block 438 | vertical-align: middle 439 | 440 | h1 441 | antialias() 442 | font-weight: bold 443 | font-family: montserrat, sans-serif 444 | font-size: 13px 445 | 446 | &, a, a:visited 447 | color: $grey 448 | a:hover 449 | color: $txt 450 | 451 | li a 452 | font-size: 0.88em 453 | color: $grey 454 | display: block 455 | 456 | &:hover 457 | color: $grey*0.4 458 | 459 | @media (min-width: 480px) /* Tablet & Desktop */ 460 | h1 461 | float: left 462 | 463 | ul, li 464 | display: block 465 | float: left 466 | 467 | ul 468 | margin-left: -15px 469 | 470 | h1 + ul 471 | border-left: solid 1px $line 472 | margin-left: 15px 473 | 474 | li 475 | border-left: solid 1px rgba(white, 0.5) 476 | border-right: solid 1px $line 477 | &:last-child 478 | border-right: 0 479 | 480 | li a 481 | padding: 0 15px 482 | 483 | @media (max-width: 480px) /* Mobile */ 484 | // Hide extra stuff on mobile 485 | .right 486 | display: none 487 | 488 | // ---------------------------------------------------------------------------- 489 | // Sidebar 490 | 491 | .menubar 492 | antialias() 493 | .section 494 | padding: $sidepad $sidepad 495 | box-sizing: border-box 496 | 497 | .section + .section 498 | border-top: solid 1px $line 499 | 500 | .section.no-line 501 | border-top: 0 502 | padding-top: 0 503 | 504 | a.big.button 505 | display: block 506 | box-sizing: border-box 507 | width: 100% 508 | padding: 10px 20px 509 | text-align: center 510 | 511 | font-weight: bold 512 | font-size: 1.1em 513 | 514 | background: transparent 515 | border: solid 3px $accent 516 | border-radius: 30px 517 | font-family: montserrat, sans-serif 518 | 519 | &, &:visited 520 | color: $accent 521 | text-decoration: none 522 | 523 | &:hover 524 | background: $accent 525 | &, &:visited 526 | color: white 527 | 528 | @media (max-width: 480px) /* Mobile */ 529 | .menubar 530 | padding: $minipad 531 | border-bottom: solid 1px $line 532 | 533 | @media (max-width: 768px) /* Mobile and tablet */ 534 | .menubar 535 | display: none 536 | 537 | @media (min-width: 768px) /* Desktop */ 538 | .content-root 539 | padding-left: $sidebar-width 540 | 541 | .menubar 542 | position: absolute 543 | left: 0 544 | top: 0 545 | bottom: 0 546 | width: $sidebar-width 547 | border-right: solid 1px $line 548 | 549 | .menubar.fixed 550 | position: fixed 551 | 552 | scrollbar() 553 | overflow-y: auto 554 | 555 | .menubar 556 | font-size: 0.9em 557 | 558 | // Menu items 559 | .menu 560 | ul.level-1 > li + li 561 | margin-top: 20px 562 | 563 | a 564 | box-sizing: border-box 565 | position: relative 566 | 567 | display: block 568 | padding-top: 1px 569 | padding-bottom: 1px 570 | margin-right: ($sidepad * -1) 571 | 572 | &, &:visited 573 | color: $accent 574 | &:hover 575 | color: $accent*0.8 576 | 577 | a.level-1 578 | font-family: montserrat, sans-serif 579 | text-transform: uppercase 580 | font-size: 0.9em 581 | font-weight: bold 582 | &, &:visited 583 | color: $grey 584 | &:hover 585 | color: $grey*0.6 586 | 587 | a.level-2 588 | font-weight: normal 589 | 590 | a.level-3 591 | font-weight: normal 592 | font-size: 0.9em 593 | padding-left: 10px 594 | 595 | a.active 596 | &, &:visited, &:hover 597 | color: $txt !important 598 | font-weight: bold !important 599 | 600 | // Indicator 601 | &:after 602 | content: '' 603 | display: block 604 | box-sizing: border-box 605 | 606 | absolute: top 10px right $sidepad 607 | 608 | width: 9px 609 | height: 3px 610 | border-radius: 2px 611 | background: $accent 612 | 613 | // ---------------------------------------------------------------------------- 614 | // Syntax highlighting 615 | 616 | code 617 | .string, .number 618 | color: #3ac 619 | .init 620 | color: #383 621 | .keyword 622 | font-weight: bold 623 | .comment 624 | color: $grey * 1.2 625 | 626 | // ---------------------------------------------------------------------------- 627 | 628 | .content 629 | .large-brief & > h1:first-child + p, 630 | > p.brief 631 | font-size: 1.3em 632 | font-family: Open Sans, sans-serif 633 | font-weight: 300 634 | 635 | // ---------------------------------------------------------------------------- 636 | 637 | .title-area 638 | min-height: 100px 639 | box-sizing: border-box 640 | antialias() 641 | text-align: center 642 | border-bottom: solid 1px $line 643 | overflow: hidden 644 | 645 | > img.bg 646 | z-index: 0 647 | 648 | // Start it off screen 649 | position: absolute 650 | left: -9999px 651 | 652 | > div 653 | position: relative 654 | z-index: 1 655 | 656 | 657 | --------------------------------------------------------------------------------