white-rabbit 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,11 @@
1
+ body {
2
+ background-color: var(--meka-body);
3
+ color: var(--meka-accent);
4
+ font-family: var(--monospace);
5
+ font-size: var(--font-size-base);
6
+ height: 100%;
7
+ line-height: 1.6;
8
+ margin: 0 auto;
9
+ max-width: 1280px;
10
+ padding: var(--spacing-4);
11
+ }
data/_sass/_grid.scss ADDED
@@ -0,0 +1,14 @@
1
+ .grid {
2
+ display: grid;
3
+ grid-gap: var(--spacing-5) var(--spacing-3);
4
+ grid-template-columns: auto;
5
+ grid-template-rows: auto;
6
+ }
7
+
8
+ .grid-12 .grid-item {
9
+ grid-column: span 12;
10
+ }
11
+
12
+ .grid-8 .grid-item {
13
+ grid-column: span 8;
14
+ }
@@ -0,0 +1,45 @@
1
+ .site-header,
2
+ .site-footer {
3
+ padding: var(--spacing-4);
4
+ }
5
+
6
+ .site-footer {
7
+ color: var(--dva-secondary-base);
8
+ text-align: center;
9
+ }
10
+
11
+ // navigation
12
+ .site-header .navigation {
13
+ display: flex;
14
+ align-items: center;
15
+ }
16
+
17
+ .site-header .logo .header,
18
+ .site-header .logo .subheader {
19
+ display: block;
20
+ }
21
+
22
+ .site-header .logo .header {
23
+ font-size: var(--font-size-5);
24
+ font-weight: 700;
25
+ }
26
+
27
+ .site-header .logo .subheader {
28
+ font-size: var(--font-size-2);
29
+ font-weight: 400;
30
+ margin-top: calc(-1*var(--spacing-1));
31
+ position: relative;
32
+ }
33
+
34
+ .site-header .links {
35
+ flex-grow: 1;
36
+ text-align: right;
37
+ }
38
+
39
+ .site-header .link {
40
+ display: inline-block;
41
+ }
42
+
43
+ .site-header .link:not(:last-child) {
44
+ margin-right: var(--spacing-3);
45
+ }
@@ -0,0 +1,87 @@
1
+ /*! minireset.css v0.0.3 | MIT License | github.com/jgthms/minireset.css */
2
+ html {
3
+ background-color: var(--meka-accent);
4
+ background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 304 304' width='304' height='304'%3E%3Cpath fill='%23ffffff' fill-opacity='0.025' d='M44.1 224a5 5 0 1 1 0 2H0v-2h44.1zm160 48a5 5 0 1 1 0 2H82v-2h122.1zm57.8-46a5 5 0 1 1 0-2H304v2h-42.1zm0 16a5 5 0 1 1 0-2H304v2h-42.1zm6.2-114a5 5 0 1 1 0 2h-86.2a5 5 0 1 1 0-2h86.2zm-256-48a5 5 0 1 1 0 2H0v-2h12.1zm185.8 34a5 5 0 1 1 0-2h86.2a5 5 0 1 1 0 2h-86.2zM258 12.1a5 5 0 1 1-2 0V0h2v12.1zm-64 208a5 5 0 1 1-2 0v-54.2a5 5 0 1 1 2 0v54.2zm48-198.2V80h62v2h-64V21.9a5 5 0 1 1 2 0zm16 16V64h46v2h-48V37.9a5 5 0 1 1 2 0zm-128 96V208h16v12.1a5 5 0 1 1-2 0V210h-16v-76.1a5 5 0 1 1 2 0zm-5.9-21.9a5 5 0 1 1 0 2H114v48H85.9a5 5 0 1 1 0-2H112v-48h12.1zm-6.2 130a5 5 0 1 1 0-2H176v-74.1a5 5 0 1 1 2 0V242h-60.1zm-16-64a5 5 0 1 1 0-2H114v48h10.1a5 5 0 1 1 0 2H112v-48h-10.1zM66 284.1a5 5 0 1 1-2 0V274H50v30h-2v-32h18v12.1zM236.1 176a5 5 0 1 1 0 2H226v94h48v32h-2v-30h-48v-98h12.1zm25.8-30a5 5 0 1 1 0-2H274v44.1a5 5 0 1 1-2 0V146h-10.1zm-64 96a5 5 0 1 1 0-2H208v-80h16v-14h-42.1a5 5 0 1 1 0-2H226v18h-16v80h-12.1zm86.2-210a5 5 0 1 1 0 2H272V0h2v32h10.1zM98 101.9V146H53.9a5 5 0 1 1 0-2H96v-42.1a5 5 0 1 1 2 0zM53.9 34a5 5 0 1 1 0-2H80V0h2v34H53.9zm60.1 3.9V66H82v64H69.9a5 5 0 1 1 0-2H80V64h32V37.9a5 5 0 1 1 2 0zM101.9 82a5 5 0 1 1 0-2H128V37.9a5 5 0 1 1 2 0V82h-28.1zm16-64a5 5 0 1 1 0-2H146v44.1a5 5 0 1 1-2 0V18h-26.1zm102.2 270a5 5 0 1 1 0 2H98v14h-2v-16h124.1zM242 149.9V160h16v34h-16v62h48v48h-2v-46h-48v-66h16v-30h-16v-12.1a5 5 0 1 1 2 0zM53.9 18a5 5 0 1 1 0-2H64V2H48V0h18v18H53.9zm112 32a5 5 0 1 1 0-2H192V0h50v2h-48v48h-28.1zm-48-48a5 5 0 0 1-9.8-2h2.07a3 3 0 1 0 5.66 0H178v34h-18V21.9a5 5 0 1 1 2 0V32h14V2h-58.1zm0 96a5 5 0 1 1 0-2H137l32-32h39V21.9a5 5 0 1 1 2 0V66h-40.17l-32 32H117.9zm28.1 90.1a5 5 0 1 1-2 0v-76.51L175.59 80H224V21.9a5 5 0 1 1 2 0V82h-49.59L146 112.41v75.69zm16 32a5 5 0 1 1-2 0v-99.51L184.59 96H300.1a5 5 0 0 1 3.9-3.9v2.07a3 3 0 0 0 0 5.66v2.07a5 5 0 0 1-3.9-3.9H185.41L162 121.41v98.69zm-144-64a5 5 0 1 1-2 0v-3.51l48-48V48h32V0h2v50H66v55.41l-48 48v2.69zM50 53.9v43.51l-48 48V208h26.1a5 5 0 1 1 0 2H0v-65.41l48-48V53.9a5 5 0 1 1 2 0zm-16 16V89.41l-34 34v-2.82l32-32V69.9a5 5 0 1 1 2 0zM12.1 32a5 5 0 1 1 0 2H9.41L0 43.41V40.6L8.59 32h3.51zm265.8 18a5 5 0 1 1 0-2h18.69l7.41-7.41v2.82L297.41 50H277.9zm-16 160a5 5 0 1 1 0-2H288v-71.41l16-16v2.82l-14 14V210h-28.1zm-208 32a5 5 0 1 1 0-2H64v-22.59L40.59 194H21.9a5 5 0 1 1 0-2H41.41L66 216.59V242H53.9zm150.2 14a5 5 0 1 1 0 2H96v-56.6L56.6 162H37.9a5 5 0 1 1 0-2h19.5L98 200.6V256h106.1zm-150.2 2a5 5 0 1 1 0-2H80v-46.59L48.59 178H21.9a5 5 0 1 1 0-2H49.41L82 208.59V258H53.9zM34 39.8v1.61L9.41 66H0v-2h8.59L32 40.59V0h2v39.8zM2 300.1a5 5 0 0 1 3.9 3.9H3.83A3 3 0 0 0 0 302.17V256h18v48h-2v-46H2v42.1zM34 241v63h-2v-62H0v-2h34v1zM17 18H0v-2h16V0h2v18h-1zm273-2h14v2h-16V0h2v16zm-32 273v15h-2v-14h-14v14h-2v-16h18v1zM0 92.1A5.02 5.02 0 0 1 6 97a5 5 0 0 1-6 4.9v-2.07a3 3 0 1 0 0-5.66V92.1zM80 272h2v32h-2v-32zm37.9 32h-2.07a3 3 0 0 0-5.66 0h-2.07a5 5 0 0 1 9.8 0zM5.9 0A5.02 5.02 0 0 1 0 5.9V3.83A3 3 0 0 0 3.83 0H5.9zm294.2 0h2.07A3 3 0 0 0 304 3.83V5.9a5 5 0 0 1-3.9-5.9zm3.9 300.1v2.07a3 3 0 0 0-1.83 1.83h-2.07a5 5 0 0 1 3.9-3.9zM97 100a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm0-16a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm16 16a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm16 16a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm0 16a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm-48 32a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm16 16a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm32 48a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm-16 16a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm32-16a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm0-32a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm16 32a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm32 16a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm0-16a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm-16-64a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm16 0a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm16 96a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm0 16a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm16 16a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm16-144a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm0 32a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm16-32a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm16-16a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm-96 0a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm0 16a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm16-32a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm96 0a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm-16-64a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm16-16a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm-32 0a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm0-16a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm-16 0a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm-16 0a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm-16 0a3 3 0 1 0 0-6 3 3 0 0 0 0 6zM49 36a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm-32 0a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm32 16a3 3 0 1 0 0-6 3 3 0 0 0 0 6zM33 68a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm16-48a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm0 240a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm16 32a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm-16-64a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm0 16a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm-16-32a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm80-176a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm16 0a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm-16-16a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm32 48a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm16-16a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm0-32a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm112 176a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm-16 16a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm0 16a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm0 16a3 3 0 1 0 0-6 3 3 0 0 0 0 6zM17 180a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm0 16a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm0-32a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm16 0a3 3 0 1 0 0-6 3 3 0 0 0 0 6zM17 84a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm32 64a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm16-16a3 3 0 1 0 0-6 3 3 0 0 0 0 6z'%3E%3C/path%3E%3C/svg%3E");
5
+ box-sizing: border-box;
6
+ }
7
+
8
+ html,
9
+ body,
10
+ p,
11
+ ol,
12
+ ul,
13
+ li,
14
+ dl,
15
+ dt,
16
+ dd,
17
+ blockquote,
18
+ figure,
19
+ fieldset,
20
+ legend,
21
+ textarea,
22
+ pre,
23
+ iframe,
24
+ hr,
25
+ h1,
26
+ h2,
27
+ h3,
28
+ h4,
29
+ h5,
30
+ h6 {
31
+ margin: 0;
32
+ padding: 0;
33
+ }
34
+
35
+ h1,
36
+ h2,
37
+ h3,
38
+ h4,
39
+ h5,
40
+ h6 {
41
+ font-weight: normal;
42
+ font-size: 100%;
43
+ }
44
+
45
+ ul {
46
+ list-style: none;
47
+ }
48
+
49
+ button,
50
+ input,
51
+ select,
52
+ textarea {
53
+ margin: 0;
54
+ }
55
+
56
+ *,
57
+ *:before,
58
+ *:after {
59
+ box-sizing: inherit;
60
+ }
61
+
62
+ img,
63
+ embed,
64
+ iframe,
65
+ object,
66
+ audio,
67
+ video {
68
+ height: auto;
69
+ max-width: 100%;
70
+ width: 100%;
71
+ vertical-align: middle;
72
+ }
73
+
74
+ iframe {
75
+ border: 0;
76
+ }
77
+
78
+ table {
79
+ border-collapse: collapse;
80
+ border-spacing: 0;
81
+ }
82
+
83
+ td,
84
+ th {
85
+ padding: 0;
86
+ text-align: left;
87
+ }
@@ -0,0 +1,10 @@
1
+ a {
2
+ color: var(--meka-accent);
3
+ font-weight: 700;
4
+ text-decoration: none;
5
+ transition: 150ms ease-in;
6
+ }
7
+
8
+ a:hover {
9
+ color: var(--meka-matrix);
10
+ }
data/_sass/app.scss ADDED
@@ -0,0 +1,13 @@
1
+ @charset "utf-8";
2
+
3
+ @import "custom-properties";
4
+ @import "resets";
5
+
6
+ @import "blocks";
7
+ @import "content";
8
+ @import "general";
9
+ @import "grid";
10
+ @import "navigation";
11
+ @import "typography";
12
+
13
+ @import "third-party/tabby";
@@ -0,0 +1,71 @@
1
+ /*!
2
+ * Tabby v11.2.0: Simple, mobile-first toggle tabs.
3
+ * (c) 2016 Chris Ferdinandi
4
+ * MIT License
5
+ * http://github.com/cferdinandi/tabby
6
+ */
7
+
8
+ /**
9
+ * Tab content
10
+ */
11
+
12
+ /* line 4, /Users/cferdinandi/Sites/tabby/src/sass/components/_tabby.scss */
13
+ .js-tabby .tabs-pane {
14
+ border: 0;
15
+ clip: rect(0 0 0 0);
16
+ height: 1px;
17
+ margin: -1px;
18
+ opacity: 0;
19
+ overflow: hidden;
20
+ padding: 0;
21
+ position: absolute;
22
+ transform: translateY(40px);
23
+ transition: opacity 250ms ease-in, transform 300ms ease-in;
24
+ }
25
+
26
+ /* line 14, /Users/cferdinandi/Sites/tabby/src/sass/components/_tabby.scss */
27
+ .js-tabby .tabs-pane.active {
28
+ clip: auto;
29
+ height: auto;
30
+ margin: 0;
31
+ opacity: 1;
32
+ overflow: visible;
33
+ position: static;
34
+ transform: translateY(0px);
35
+ }
36
+
37
+ /* line 23, /Users/cferdinandi/Sites/tabby/src/sass/components/_tabby.scss */
38
+ .js-tabby .tabs-pane:focus {
39
+ outline: none;
40
+ }
41
+
42
+ // custom styling
43
+ .tabs {
44
+ margin-bottom: var(--spacing-4);
45
+ text-align: center;
46
+ }
47
+
48
+ .tabs li {
49
+ display: inline-block;
50
+ font-size: var(--font-size-1);
51
+ margin-right: var(--spacing-3);
52
+ }
53
+
54
+ .tabs a {
55
+ background-color: var(--meka-body);
56
+ color: var(--meka-accent);
57
+ padding: var(--spacing-2) var(--spacing-3);
58
+ }
59
+
60
+ .tabs a:hover,
61
+ .tabs .active a {
62
+ color: var(--meka-body);
63
+ }
64
+
65
+ .tabs a:hover {
66
+ background-color: var(--dva-secondary-dark);
67
+ }
68
+
69
+ .tabs .active a {
70
+ background-color: var(--meka-matrix);
71
+ }
Binary file
Binary file
Binary file
Binary file
Binary file
@@ -0,0 +1,518 @@
1
+ /*!
2
+ * Tabby v11.2.0: Simple, mobile-first toggle tabs.
3
+ * (c) 2016 Chris Ferdinandi
4
+ * MIT License
5
+ * http://github.com/cferdinandi/tabby
6
+ */
7
+
8
+ (function (root, factory) {
9
+ if (typeof define === 'function' && define.amd) {
10
+ define([], factory(root));
11
+ } else if (typeof exports === 'object') {
12
+ module.exports = factory(root);
13
+ } else {
14
+ root.tabby = factory(root);
15
+ }
16
+ })(typeof global !== 'undefined' ? global : this.window || this.global, (function (root) {
17
+
18
+ 'use strict';
19
+
20
+ //
21
+ // Variables
22
+ //
23
+
24
+ var tabby = {}; // Object for public APIs
25
+ var supports = 'querySelector' in document && 'addEventListener' in root && 'classList' in document.createElement('_') && 'onhashchange' in root; // Feature test
26
+ var settings, tab;
27
+
28
+ // Default settings
29
+ var defaults = {
30
+ selectorToggle: '[data-tab]',
31
+ selectorToggleGroup: '[data-tabs]',
32
+ selectorContent: '[data-tabs-pane]',
33
+ selectorContentGroup: '[data-tabs-content]',
34
+ toggleActiveClass: 'active',
35
+ contentActiveClass: 'active',
36
+ initClass: 'js-tabby',
37
+ stopVideo: true,
38
+ callback: function () {}
39
+ };
40
+
41
+
42
+ //
43
+ // Methods
44
+ //
45
+
46
+ /**
47
+ * A simple forEach() implementation for Arrays, Objects and NodeLists
48
+ * @private
49
+ * @param {Array|Object|NodeList} collection Collection of items to iterate
50
+ * @param {Function} callback Callback function for each iteration
51
+ * @param {Array|Object|NodeList} scope Object/NodeList/Array that forEach is iterating over (aka `this`)
52
+ */
53
+ var forEach = function (collection, callback, scope) {
54
+ if (Object.prototype.toString.call(collection) === '[object Object]') {
55
+ for (var prop in collection) {
56
+ if (Object.prototype.hasOwnProperty.call(collection, prop)) {
57
+ callback.call(scope, collection[prop], prop, collection);
58
+ }
59
+ }
60
+ } else {
61
+ for (var i = 0, len = collection.length; i < len; i++) {
62
+ callback.call(scope, collection[i], i, collection);
63
+ }
64
+ }
65
+ };
66
+
67
+ /**
68
+ * Merge defaults with user options
69
+ * @private
70
+ * @param {Object} defaults Default settings
71
+ * @param {Object} options User options
72
+ * @returns {Object} Merged values of defaults and options
73
+ */
74
+ var extend = function () {
75
+
76
+ // Variables
77
+ var extended = {};
78
+ var deep = false;
79
+ var i = 0;
80
+ var length = arguments.length;
81
+
82
+ // Check if a deep merge
83
+ if (Object.prototype.toString.call(arguments[0]) === '[object Boolean]') {
84
+ deep = arguments[0];
85
+ i++;
86
+ }
87
+
88
+ // Merge the object into the extended object
89
+ var merge = function (obj) {
90
+ for (var prop in obj) {
91
+ if (Object.prototype.hasOwnProperty.call(obj, prop)) {
92
+ // If deep merge and property is an object, merge properties
93
+ if (deep && Object.prototype.toString.call(obj[prop]) === '[object Object]') {
94
+ extended[prop] = extend(true, extended[prop], obj[prop]);
95
+ } else {
96
+ extended[prop] = obj[prop];
97
+ }
98
+ }
99
+ }
100
+ };
101
+
102
+ // Loop through each object and conduct a merge
103
+ for (; i < length; i++) {
104
+ var obj = arguments[i];
105
+ merge(obj);
106
+ }
107
+
108
+ return extended;
109
+
110
+ };
111
+
112
+ /**
113
+ * Get the closest matching element up the DOM tree.
114
+ * @private
115
+ * @param {Element} elem Starting element
116
+ * @param {String} selector Selector to match against
117
+ * @return {Boolean|Element} Returns null if not match found
118
+ */
119
+ var getClosest = function (elem, selector) {
120
+
121
+ // Element.matches() polyfill
122
+ if (!Element.prototype.matches) {
123
+ Element.prototype.matches =
124
+ Element.prototype.matchesSelector ||
125
+ Element.prototype.mozMatchesSelector ||
126
+ Element.prototype.msMatchesSelector ||
127
+ Element.prototype.oMatchesSelector ||
128
+ Element.prototype.webkitMatchesSelector ||
129
+ function (s) {
130
+ var matches = (this.document || this.ownerDocument).querySelectorAll(s),
131
+ i = matches.length;
132
+ while (--i >= 0 && matches.item(i) !== this) {}
133
+ return i > -1;
134
+ };
135
+ }
136
+
137
+ // Get closest match
138
+ for (; elem && elem !== document; elem = elem.parentNode) {
139
+ if (elem.matches(selector)) return elem;
140
+ }
141
+
142
+ return null;
143
+
144
+ };
145
+
146
+ /**
147
+ * Escape special characters for use with querySelector
148
+ * @public
149
+ * @param {String} id The anchor ID to escape
150
+ * @author Mathias Bynens
151
+ * @link https://github.com/mathiasbynens/CSS.escape
152
+ */
153
+ var escapeCharacters = function (id) {
154
+
155
+ // Remove leading hash
156
+ if (id.charAt(0) === '#') {
157
+ id = id.substr(1);
158
+ }
159
+
160
+ var string = String(id);
161
+ var length = string.length;
162
+ var index = -1;
163
+ var codeUnit;
164
+ var result = '';
165
+ var firstCodeUnit = string.charCodeAt(0);
166
+ while (++index < length) {
167
+ codeUnit = string.charCodeAt(index);
168
+ // Note: there’s no need to special-case astral symbols, surrogate
169
+ // pairs, or lone surrogates.
170
+
171
+ // If the character is NULL (U+0000), then throw an
172
+ // `InvalidCharacterError` exception and terminate these steps.
173
+ if (codeUnit === 0x0000) {
174
+ throw new InvalidCharacterError(
175
+ 'Invalid character: the input contains U+0000.'
176
+ );
177
+ }
178
+
179
+ if (
180
+ // If the character is in the range [\1-\1F] (U+0001 to U+001F) or is
181
+ // U+007F, […]
182
+ (codeUnit >= 0x0001 && codeUnit <= 0x001F) || codeUnit == 0x007F ||
183
+ // If the character is the first character and is in the range [0-9]
184
+ // (U+0030 to U+0039), […]
185
+ (index === 0 && codeUnit >= 0x0030 && codeUnit <= 0x0039) ||
186
+ // If the character is the second character and is in the range [0-9]
187
+ // (U+0030 to U+0039) and the first character is a `-` (U+002D), […]
188
+ (
189
+ index === 1 &&
190
+ codeUnit >= 0x0030 && codeUnit <= 0x0039 &&
191
+ firstCodeUnit === 0x002D
192
+ )
193
+ ) {
194
+ // http://dev.w3.org/csswg/cssom/#escape-a-character-as-code-point
195
+ result += '\\' + codeUnit.toString(16) + ' ';
196
+ continue;
197
+ }
198
+
199
+ // If the character is not handled by one of the above rules and is
200
+ // greater than or equal to U+0080, is `-` (U+002D) or `_` (U+005F), or
201
+ // is in one of the ranges [0-9] (U+0030 to U+0039), [A-Z] (U+0041 to
202
+ // U+005A), or [a-z] (U+0061 to U+007A), […]
203
+ if (
204
+ codeUnit >= 0x0080 ||
205
+ codeUnit === 0x002D ||
206
+ codeUnit === 0x005F ||
207
+ codeUnit >= 0x0030 && codeUnit <= 0x0039 ||
208
+ codeUnit >= 0x0041 && codeUnit <= 0x005A ||
209
+ codeUnit >= 0x0061 && codeUnit <= 0x007A
210
+ ) {
211
+ // the character itself
212
+ result += string.charAt(index);
213
+ continue;
214
+ }
215
+
216
+ // Otherwise, the escaped character.
217
+ // http://dev.w3.org/csswg/cssom/#escape-a-character
218
+ result += '\\' + string.charAt(index);
219
+
220
+ }
221
+
222
+ return '#' + result;
223
+
224
+ };
225
+
226
+ /**
227
+ * Stop YouTube, Vimeo, and HTML5 videos from playing when leaving the slide
228
+ * @private
229
+ * @param {Element} content The content container the video is in
230
+ * @param {String} activeClass The class asigned to expanded content areas
231
+ */
232
+ var stopVideos = function (content, settings) {
233
+
234
+ // Check if stop video enabled
235
+ if (!settings.stopVideo) return;
236
+
237
+ // Only run if content container is closed
238
+ if (content.classList.contains(settings.contentActiveClass)) return;
239
+
240
+ // Check if the video is an iframe or HTML5 video
241
+ var iframe = content.querySelector('iframe');
242
+ var video = content.querySelector('video');
243
+
244
+ // Stop the video
245
+ if (iframe) {
246
+ var iframeSrc = iframe.src;
247
+ iframe.src = iframeSrc;
248
+ }
249
+ if (video) {
250
+ video.pause();
251
+ }
252
+
253
+ };
254
+
255
+ /**
256
+ * Add focus to tab
257
+ * @private
258
+ * @param {node} tab The content to bring into focus
259
+ * @param {object} settings Options
260
+ */
261
+ var adjustFocus = function (tab, settings) {
262
+
263
+ if (tab.hasAttribute('data-tab-no-focus')) return;
264
+
265
+ // If tab is closed, remove tabindex
266
+ if (!tab.classList.contains(settings.contentActiveClass)) {
267
+ if (tab.hasAttribute('data-tab-focused')) {
268
+ tab.removeAttribute('tabindex');
269
+ }
270
+ return;
271
+ }
272
+
273
+ // Get current position on the page
274
+ var position = {
275
+ x: root.pageXOffset,
276
+ y: root.pageYOffset
277
+ };
278
+
279
+ // Set focus and reset position to account for page jump on focus
280
+ tab.focus();
281
+ if (document.activeElement.id !== tab.id) {
282
+ tab.setAttribute('tabindex', '-1');
283
+ tab.setAttribute('data-tab-focused', true);
284
+ tab.focus();
285
+ }
286
+ root.scrollTo(position.x, position.y);
287
+
288
+ };
289
+
290
+ /**
291
+ * Toggle tab toggle active state
292
+ * @private
293
+ * @param {Node} toggle The toggle element
294
+ * @param {Object} settings
295
+ */
296
+ var toggleToggles = function (toggle, settings) {
297
+
298
+ // Variables
299
+ var toggleGroup = getClosest(toggle, settings.selectorToggleGroup); // The parent for the toggle group
300
+ if (!toggleGroup) return;
301
+ var toggles = toggleGroup.querySelectorAll(settings.selectorToggle); // The toggles in the group
302
+ var toggleList;
303
+
304
+ // Show or hide each toggle
305
+ // @todo Start here
306
+ forEach(toggles, (function (item) {
307
+
308
+ // If this is the selected toggle, activate it
309
+ if (item.hash === toggle.hash) {
310
+
311
+ // Add active class
312
+ item.classList.add(settings.toggleActiveClass);
313
+
314
+ // If toggle is a list item, activate <li> element, too
315
+ toggleList = getClosest(item, 'li');
316
+ if (toggleList) {
317
+ toggleList.classList.add(settings.toggleActiveClass);
318
+ }
319
+
320
+ return;
321
+
322
+ }
323
+
324
+ // Otherwise, deactivate it
325
+ item.classList.remove(settings.toggleActiveClass);
326
+ toggleList = getClosest(item, 'li');
327
+ if (toggleList) {
328
+ toggleList.classList.remove(settings.toggleActiveClass);
329
+ }
330
+
331
+ }));
332
+
333
+ };
334
+
335
+ /**
336
+ * Toggle tab active state
337
+ * @private
338
+ * @param {String} tabID The ID of the tab to activate
339
+ * @param {Object} settings
340
+ */
341
+ var toggleTabs = function (tabID, settings) {
342
+
343
+ // Variables
344
+ var tab = document.querySelector(escapeCharacters(tabID)); // The selected tab
345
+ if (!tab) return;
346
+ var tabGroup = getClosest(tab, settings.selectorContentGroup); // The parent for the tab group
347
+ if (!tabGroup) return;
348
+ var tabs = tabGroup.querySelectorAll(settings.selectorContent); // The tabs in the group
349
+
350
+ // Show or hide each tab
351
+ forEach(tabs, (function (tab) {
352
+
353
+ // If this is the selected tab, show it
354
+ if (tab.id === tabID.substring(1)) {
355
+ tab.classList.add(settings.contentActiveClass);
356
+ adjustFocus(tab, settings);
357
+ return;
358
+ }
359
+
360
+ // Otherwise, hide it
361
+ tab.classList.remove(settings.contentActiveClass);
362
+ stopVideos(tab, settings);
363
+ adjustFocus(tab, settings);
364
+
365
+ }));
366
+
367
+ };
368
+
369
+ /**
370
+ * Show a tab and hide all others
371
+ * @public
372
+ * @param {Element} toggle The element that toggled the show tab event
373
+ * @param {String} tabID The ID of the tab to show
374
+ * @param {Object} options
375
+ */
376
+ tabby.toggleTab = function (tabID, toggle, options) {
377
+
378
+ // Selectors and variables
379
+ var localSettings = extend(settings || defaults, options || {}); // Merge user options with defaults
380
+ var tabs = document.querySelectorAll(escapeCharacters(tabID)); // Get tab content
381
+
382
+ // Toggle visibility of the toggles and tabs
383
+ toggleTabs(tabID, localSettings);
384
+ if (toggle) {
385
+ toggleToggles(toggle, localSettings);
386
+ }
387
+
388
+ // Run callbacks after toggling tab
389
+ localSettings.callback(tabs, toggle);
390
+
391
+ };
392
+
393
+ /**
394
+ * Handle has change event
395
+ * @private
396
+ */
397
+ var hashChangeHandler = function (event) {
398
+
399
+ // Get hash from URL
400
+ var hash = root.location.hash;
401
+
402
+ // If clicked tab is cached, reset it's ID
403
+ if (tab) {
404
+ tab.id = tab.getAttribute('data-tab-id');
405
+ tab = null;
406
+ }
407
+
408
+ // If there's a URL hash, activate tab with matching ID
409
+ if (!hash) return;
410
+ var toggle = document.querySelector(settings.selectorToggle + '[href*="' + hash + '"]');
411
+ tabby.toggleTab(hash, toggle);
412
+
413
+ };
414
+
415
+ /**
416
+ * Handle toggle click events
417
+ * @private
418
+ */
419
+ var clickHandler = function (event) {
420
+
421
+ // Don't run if right-click or command/control + click
422
+ if (event.button !== 0 || event.metaKey || event.ctrlKey) return;
423
+
424
+ // Check if event target is a tab toggle
425
+ var toggle = getClosest(event.target, settings.selectorToggle);
426
+ if (!toggle || !toggle.hash) return;
427
+
428
+ // Don't run if toggle points to currently open tab
429
+ if (toggle.hash === root.location.hash) {
430
+ event.preventDefault();
431
+ return;
432
+ }
433
+
434
+ // Get the tab content
435
+ tab = document.querySelector(toggle.hash);
436
+
437
+ // If tab content exists, save the ID as a data attribute and remove it (prevents scroll jump)
438
+ if (!tab) return;
439
+ tab.setAttribute('data-tab-id', tab.id);
440
+ tab.id = '';
441
+
442
+ };
443
+
444
+ /**
445
+ * Handle content focus events
446
+ * @private
447
+ */
448
+ var focusHandler = function (event) {
449
+
450
+ // Only run if the focused content is in a tab
451
+ tab = getClosest(event.target, settings.selectorContent);
452
+ if (!tab) return;
453
+
454
+ // Don't run if the content area is already open
455
+ if (tab.classList.contains(settings.contentActiveClass)) return;
456
+
457
+ // Store tab ID to variable and remove it from the tab
458
+ var hash = tab.id;
459
+ tab.setAttribute('data-tab-id', hash);
460
+ tab.setAttribute('data-tab-no-focus', true);
461
+ tab.id = '';
462
+
463
+ // Change the hash
464
+ location.hash = hash;
465
+
466
+ };
467
+
468
+ /**
469
+ * Destroy the current initialization.
470
+ * @public
471
+ */
472
+ tabby.destroy = function () {
473
+ if (!settings) return;
474
+ document.documentElement.classList.remove(settings.initClass);
475
+ document.removeEventListener('click', clickHandler, false);
476
+ document.removeEventListener('focus', focusHandler, true);
477
+ root.removeEventListener('hashchange', hashChangeHandler, false);
478
+ settings = null;
479
+ tab = null;
480
+ };
481
+
482
+ /**
483
+ * Initialize Tabby
484
+ * @public
485
+ * @param {Object} options User settings
486
+ */
487
+ tabby.init = function (options) {
488
+
489
+ // feature test
490
+ if (!supports) return;
491
+
492
+ // Destroy any existing initializations
493
+ tabby.destroy();
494
+
495
+ // Merge user options with defaults
496
+ settings = extend(defaults, options || {});
497
+
498
+ // Add class to HTML element to activate conditional CSS
499
+ document.documentElement.classList.add(settings.initClass);
500
+
501
+ // Listen for all click events
502
+ document.addEventListener('click', clickHandler, false);
503
+ document.addEventListener('focus', focusHandler, true);
504
+ root.addEventListener('hashchange', hashChangeHandler, false);
505
+
506
+ // If URL has a hash, activate hashed tab by default
507
+ hashChangeHandler();
508
+
509
+ };
510
+
511
+
512
+ //
513
+ // Public APIs
514
+ //
515
+
516
+ return tabby;
517
+
518
+ }));