aboutsummaryrefslogtreecommitdiffstats
path: root/demo
diff options
context:
space:
mode:
authorSam Potts <me@sampotts.me>2016-08-20 17:46:05 +1000
committerSam Potts <me@sampotts.me>2016-08-20 17:46:05 +1000
commitfc45ab48c932c6ecb810ed6456ff824ef43be73c (patch)
tree557e7520a47f00c89410f124d418722627e0e86e /demo
parent6425a33ccd015a4e21545669c0774e2f12d1c47f (diff)
parent58e9b02405ccd3c3502bbf221097aa0604796769 (diff)
downloadplyr-fc45ab48c932c6ecb810ed6456ff824ef43be73c.tar.lz
plyr-fc45ab48c932c6ecb810ed6456ff824ef43be73c.tar.xz
plyr-fc45ab48c932c6ecb810ed6456ff824ef43be73c.zip
Merge branch 'master' into develop
# Conflicts: # src/js/plyr.js
Diffstat (limited to 'demo')
-rw-r--r--demo/dist/demo.css1
-rw-r--r--demo/dist/demo.js1
-rw-r--r--demo/dist/demo.svg1
-rw-r--r--demo/error.html18
-rw-r--r--demo/index.html88
-rw-r--r--demo/src/js/lib/classlist.js237
-rw-r--r--demo/src/js/main.js185
-rw-r--r--demo/src/less/components/base.less47
-rw-r--r--demo/src/less/components/buttons.less172
-rw-r--r--demo/src/less/components/error.less19
-rw-r--r--demo/src/less/components/examples.less51
-rw-r--r--demo/src/less/components/icons.less26
-rw-r--r--demo/src/less/components/type.less75
-rw-r--r--demo/src/less/demo.less26
-rw-r--r--demo/src/less/lib/animation.less9
-rw-r--r--demo/src/less/lib/fontface.less18
-rw-r--r--demo/src/less/lib/mixins.less41
-rw-r--r--demo/src/less/lib/normalize.less406
-rw-r--r--demo/src/less/variables.less48
-rwxr-xr-xdemo/src/sprite/icon-github.svg12
-rwxr-xr-xdemo/src/sprite/icon-twitter.svg11
-rwxr-xr-xdemo/src/sprite/icon-vimeo.svg9
-rwxr-xr-xdemo/src/sprite/icon-youtube.svg9
23 files changed, 1510 insertions, 0 deletions
diff --git a/demo/dist/demo.css b/demo/dist/demo.css
new file mode 100644
index 00000000..302747cb
--- /dev/null
+++ b/demo/dist/demo.css
@@ -0,0 +1 @@
+/*! normalize.css v2.1.3 | MIT License | git.io/normalize */a.logo,img,legend{border:0}a,h1,h2{color:#3498db}article,aside,details,figcaption,figure,footer,header,hgroup,main,nav,section,small,summary{display:block}body,figure,li,ul{margin:0}[hidden],template{display:none}li,nav ul,ul{list-style:none;padding:0}legend,li,nav ul,ul{padding:0}.btn__bar,sub,sup{position:relative}audio,canvas,video{display:inline-block}audio:not([controls]){display:none;height:0}html{font-family:sans-serif;-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%}a{background:0 0;text-decoration:none;border-bottom:1px dotted currentColor;transition:background .3s ease,color .3s ease,border .3s ease}a:active,a:hover{outline:0}abbr[title]{border-bottom:1px dotted}b,strong{font-weight:700}dfn{font-style:italic}hr{box-sizing:content-box;height:0}mark{background:#ff0;color:#000}code,kbd,pre,samp{font-family:monospace,serif;font-size:1em}pre{white-space:pre-wrap}.btn__bar,nav li{white-space:nowrap}q{quotes:"\201C" "\201D" "\2018" "\2019"}sub,sup{font-size:75%;line-height:0;vertical-align:baseline}sup{top:-.5em}sub{bottom:-.25em}svg:not(:root){overflow:hidden}fieldset{border:1px solid silver;margin:0 2px;padding:.35em .625em .75em}button,input,select,textarea{font-family:inherit;font-size:100%;margin:0}button,input{line-height:normal}button,select{text-transform:none}button,html input[type=button],input[type=reset],input[type=submit]{-webkit-appearance:button;cursor:pointer}button[disabled],html input[disabled]{cursor:default}input[type=checkbox],input[type=radio]{box-sizing:border-box;padding:0}input[type=search]{-webkit-appearance:textfield;box-sizing:content-box}input[type=search]::-webkit-search-cancel-button,input[type=search]::-webkit-search-decoration{-webkit-appearance:none}button::-moz-focus-inner,input::-moz-focus-inner{border:0;padding:0}textarea{overflow:auto;vertical-align:top}table{border-collapse:collapse;border-spacing:0}@-webkit-keyframes fade-in{0%{opacity:0}100%{opacity:1}}@keyframes fade-in{0%{opacity:0}100%{opacity:1}}@font-face{font-family:Avenir;src:url(//cdn.plyr.io/fonts/avenir-medium.woff2) format("woff2"),url(//cdn.plyr.io/fonts/avenir-medium.woff) format("woff");font-style:normal;font-weight:500}@font-face{font-family:Avenir;src:url(//cdn.plyr.io/fonts/avenir-bold.woff2) format("woff2"),url(//cdn.plyr.io/fonts/avenir-bold.woff) format("woff");font-style:normal;font-weight:700}html{font-size:100%;height:100%;background:fixed #f2f5f7}body{font-family:Avenir,"Helvetica Neue",Helvetica,Arial,sans-serif;line-height:1.5;text-align:center;color:#55646b;font-weight:500;-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased;padding:10px}h1,h2{letter-spacing:-.025em;margin:0 0 10px;line-height:1.2;font-weight:700}h1{font-size:64px;font-size:4rem}p,small{margin:0 0 20px}small{padding:0 10px;font-size:14px;font-size:.875rem}a:focus,a:hover{color:#343f4a;border-bottom-color:transparent}a:focus{outline:#343f4a dotted thin;outline-offset:1px}.color--vimeo{color:#19b7ed}.color--youtube{color:#cc181e}*,::after,::before{box-sizing:border-box}.btn__bar ul,nav li{display:inline-block}header{padding:20px;margin-bottom:20px}header p{font-size:18px;font-size:1.125rem}section{padding-bottom:20px}@media (min-width:480px){header{padding-top:60px;padding-bottom:60px}section{padding-bottom:40px}}.icon{fill:currentColor;width:18px;height:18px;vertical-align:-3px}.btn,.btn__count,.error main,video{vertical-align:middle}a svg,button svg,label svg{pointer-events:none}.btn .icon,a .icon{margin-right:10px}.btn:not(.btn-large) .icon{width:16px;height:16px}nav ul{margin:0;font-size:0}nav li{margin-top:10px;font-size:16px;font-size:1rem}nav li+li{margin-left:20px}.btn__bar{margin:0 auto 20px;max-width:1200px}.btn__bar::before{content:"";position:absolute;top:50%;left:0;right:0;height:1px;background:#dbe3e8}.btn__bar ul{position:relative;z-index:1;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.btn__bar li{margin:0}.btn__bar li:first-child .btn{border-radius:4px 0 0 4px}.btn__bar li:last-child .btn{border-radius:0 4px 4px 0}.btn__bar li+li .btn{margin-left:-1px}.btn__bar li.active .btn{position:relative;z-index:1}.btn__bar li.active .btn .icon{color:inherit}.btn__bar li.active+li .btn:hover{z-index:0}.btn__bar .btn{position:relative;display:block;border-radius:0}.btn__bar .btn:focus,.btn__bar .btn:hover{z-index:1}@media (min-width:560px){.btn__bar{margin-bottom:40px}}.btn,.btn__count{display:inline-block;border-radius:4px;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;font-weight:700}.btn{padding:10px 12px;background:linear-gradient(#f8fafb,#e9eef1);border:1px solid #cbd0d3;box-shadow:0 1px 1px rgba(0,0,0,.05);text-shadow:0 1px 1px #fff;color:#55646b;transition:background .1s ease,color .1s ease;font-size:14px;font-size:.875rem}.btn:focus,.btn:hover{border-color:#b5bcc0;color:#55646b;outline:0}.btn--large{padding:10px 20px;font-size:16px;font-size:1rem}.btn--primary,.btn__bar li.active .btn{background-image:linear-gradient(#3498db,#258cd1);background-color:#3498db;border-color:#217dbb;box-shadow:0 1px 1px rgba(0,0,0,.15);text-shadow:0 1px 1px rgba(0,0,0,.1);color:#fff}.btn--primary:focus,.btn--primary:hover{color:#fff;border-color:#196090}.btn--youtube .icon{color:#cc181e}.btn--vimeo .icon{color:#19b7ed}.btn--twitter .icon{color:#4BAAF4}.btn__count{position:relative;margin-left:10px;padding:10px 15px;background:#fff;border:1px solid #cbd0d3}.btn__count::before,.plyr__video-wrapper::after{content:"";position:absolute}.btn__count::before{display:block;width:8px;height:8px;left:1px;top:50%;margin-top:-4px;background:inherit;border:inherit;border-width:1px 0 0 1px;-webkit-transform:rotate(-45deg) translate(-50%,-50%);transform:rotate(-45deg) translate(-50%,-50%)}.error body,html.error{height:100%}.error body{width:100%;display:table;table-layout:fixed}.error main{display:table-cell;width:100%}section{margin:0 auto 20px;max-width:1200px}video{max-width:100%}.plyr{margin:0 auto;border-radius:6px}.plyr--audio{max-width:520px}.plyr__video-wrapper::after{pointer-events:none;top:0;bottom:0;left:0;right:0;border:1px solid rgba(0,0,0,.15);border-radius:inherit}.plyr__cite{display:none;margin-top:20px}.plyr__cite .icon{margin-right:5px}.plyr--audio~ul .plyr__cite--audio,.plyr--video:not(.plyr--youtube):not(.plyr--vimeo)~ul .plyr__cite--video,.plyr--vimeo~ul .plyr__cite--vimeo,.plyr--youtube~ul .plyr__cite--youtube{display:block} \ No newline at end of file
diff --git a/demo/dist/demo.js b/demo/dist/demo.js
new file mode 100644
index 00000000..c30c1cd3
--- /dev/null
+++ b/demo/dist/demo.js
@@ -0,0 +1 @@
+"document"in self&&("classList"in document.createElement("_")?!function(){"use strict";var e=document.createElement("_");if(e.classList.add("c1","c2"),!e.classList.contains("c2")){var t=function(e){var t=DOMTokenList.prototype[e];DOMTokenList.prototype[e]=function(e){var i,o=arguments.length;for(i=0;o>i;i++)e=arguments[i],t.call(this,e)}};t("add"),t("remove")}if(e.classList.toggle("c3",!1),e.classList.contains("c3")){var i=DOMTokenList.prototype.toggle;DOMTokenList.prototype.toggle=function(e,t){return 1 in arguments&&!this.contains(e)==!t?t:i.call(this,e)}}e=null}():!function(e){"use strict";if("Element"in e){var t="classList",i="prototype",o=e.Element[i],n=Object,s=String[i].trim||function(){return this.replace(/^\s+|\s+$/g,"")},r=Array[i].indexOf||function(e){for(var t=0,i=this.length;i>t;t++)if(t in this&&this[t]===e)return t;return-1},a=function(e,t){this.name=e,this.code=DOMException[e],this.message=t},c=function(e,t){if(""===t)throw new a("SYNTAX_ERR","An invalid or illegal string was specified");if(/\s/.test(t))throw new a("INVALID_CHARACTER_ERR","String contains an invalid character");return r.call(e,t)},l=function(e){for(var t=s.call(e.getAttribute("class")||""),i=t?t.split(/\s+/):[],o=0,n=i.length;n>o;o++)this.push(i[o]);this._updateClassName=function(){e.setAttribute("class",this.toString())}},u=l[i]=[],d=function(){return new l(this)};if(a[i]=Error[i],u.item=function(e){return this[e]||null},u.contains=function(e){return e+="",-1!==c(this,e)},u.add=function(){var e,t=arguments,i=0,o=t.length,n=!1;do e=t[i]+"",-1===c(this,e)&&(this.push(e),n=!0);while(++i<o);n&&this._updateClassName()},u.remove=function(){var e,t,i=arguments,o=0,n=i.length,s=!1;do for(e=i[o]+"",t=c(this,e);-1!==t;)this.splice(t,1),s=!0,t=c(this,e);while(++o<n);s&&this._updateClassName()},u.toggle=function(e,t){e+="";var i=this.contains(e),o=i?t!==!0&&"remove":t!==!1&&"add";return o&&this[o](e),t===!0||t===!1?t:!i},u.toString=function(){return this.join(" ")},n.defineProperty){var p={get:d,enumerable:!0,configurable:!0};try{n.defineProperty(o,t,p)}catch(h){-2146823252===h.number&&(p.enumerable=!1,n.defineProperty(o,t,p))}}else n[i].__defineGetter__&&o.__defineGetter__(t,d)}}(self)),function(){function e(e,t,i){if(e)if(e.classList)e.classList[i?"add":"remove"](t);else{var o=(" "+e.className+" ").replace(/\s+/g," ").replace(" "+t+" ","");e.className=o+(i?" "+t:"")}}function t(t,i){if(t in s&&(i||t!=r)&&(r.length||t!=s.video)){switch(t){case s.video:o.source({type:"video",title:"View From A Blue Moon",sources:[{src:"https://cdn.selz.com/plyr/1.5/View_From_A_Blue_Moon_Trailer-HD.mp4",type:"video/mp4"},{src:"https://cdn.selz.com/plyr/1.5/View_From_A_Blue_Moon_Trailer-HD.webm",type:"video/webm"}],poster:"https://cdn.selz.com/plyr/1.5/View_From_A_Blue_Moon_Trailer-HD.jpg",tracks:[{kind:"captions",label:"English",srclang:"en",src:"https://cdn.selz.com/plyr/1.5/View_From_A_Blue_Moon_Trailer-HD.en.vtt","default":!0}]});break;case s.audio:o.source({type:"audio",title:"Kishi Bashi &ndash; &ldquo;It All Began With A Burst&rdquo;",sources:[{src:"https://cdn.selz.com/plyr/1.5/Kishi_Bashi_-_It_All_Began_With_a_Burst.mp3",type:"audio/mp3"},{src:"https://cdn.selz.com/plyr/1.5/Kishi_Bashi_-_It_All_Began_With_a_Burst.ogg",type:"audio/ogg"}]});break;case s.youtube:o.source({type:"video",title:"View From A Blue Moon",sources:[{src:"bTqVqk7FSmY",type:"youtube"}]});break;case s.vimeo:o.source({type:"video",title:"View From A Blue Moon",sources:[{src:"143418951",type:"vimeo"}]})}r=t;for(var a=n.length-1;a>=0;a--)e(n[a].parentElement,"active",!1);e(document.querySelector('[data-source="'+t+'"]').parentElement,"active",!0)}}document.body.addEventListener("ready",function(e){console.log(e)});var i=plyr.setup({debug:!0,title:"Video demo",iconUrl:"../dist/plyr.svg",tooltips:{controls:!0},captions:{defaultActive:!0}});plyr.loadSprite("dist/demo.svg");for(var o=i[0].plyr,n=document.querySelectorAll("[data-source]"),s={video:"video",audio:"audio",youtube:"youtube",vimeo:"vimeo"},r=window.location.hash.replace("#",""),a=window.history&&window.history.pushState,c=n.length-1;c>=0;c--)n[c].addEventListener("click",function(){var e=this.getAttribute("data-source");t(e),a&&history.pushState({type:e},"","#"+e)});if(window.addEventListener("popstate",function(e){e.state&&"type"in e.state&&t(e.state.type)}),a){var l=!r.length;l&&(r=s.video),r in s&&history.replaceState({type:r},"",l?"":"#"+r),r!==s.video&&t(r,!0)}}(),document.domain.indexOf("plyr.io")>-1&&(!function(e,t,i,o,n,s,r){e.GoogleAnalyticsObject=n,e[n]=e[n]||function(){(e[n].q=e[n].q||[]).push(arguments)},e[n].l=1*new Date,s=t.createElement(i),r=t.getElementsByTagName(i)[0],s.async=1,s.src=o,r.parentNode.insertBefore(s,r)}(window,document,"script","//www.google-analytics.com/analytics.js","ga"),ga("create","UA-40881672-11","auto"),ga("send","pageview")); \ No newline at end of file
diff --git a/demo/dist/demo.svg b/demo/dist/demo.svg
new file mode 100644
index 00000000..6f09b44b
--- /dev/null
+++ b/demo/dist/demo.svg
@@ -0,0 +1 @@
+<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg xmlns="http://www.w3.org/2000/svg"><symbol id="icon-github" viewBox="0 0 16 16"><path fill-rule="evenodd" clip-rule="evenodd" d="M8 .2c-4.4 0-8 3.6-8 8 0 3.5 2.3 6.5 5.5 7.6.4.1.5-.2.5-.4V14c-2.2.5-2.7-1-2.7-1-.4-.9-.9-1.2-.9-1.2-.7-.5.1-.5.1-.5.8.1 1.2.8 1.2.8.7 1.3 1.9.9 2.3.7.1-.5.3-.9.5-1.1-1.8-.2-3.6-.9-3.6-4 0-.9.3-1.6.8-2.1-.1-.2-.4-1 .1-2.1 0 0 .7-.2 2.2.8.6-.2 1.3-.3 2-.3s1.4.1 2 .3c1.5-1 2.2-.8 2.2-.8.4 1.1.2 1.9.1 2.1.5.6.8 1.3.8 2.1 0 3.1-1.9 3.7-3.7 3.9.3.4.6.9.6 1.6v2.2c0 .2.1.5.6.4 3.2-1.1 5.5-4.1 5.5-7.6-.1-4.4-3.7-8-8.1-8z"/></symbol><symbol id="icon-twitter" viewBox="0 0 16 16"><title>Twitter</title><path d="M16 3c-.6.3-1.2.4-1.9.5.7-.4 1.2-1 1.4-1.8-.6.4-1.3.6-2.1.8-.6-.6-1.5-1-2.4-1-1.7 0-3.2 1.5-3.2 3.3 0 .3 0 .5.1.7-2.7-.1-5.2-1.4-6.8-3.4-.3.5-.4 1-.4 1.7 0 1.1.6 2.1 1.5 2.7-.5 0-1-.2-1.5-.4C.7 7.7 1.8 9 3.3 9.3c-.3.1-.6.1-.9.1-.2 0-.4 0-.6-.1.4 1.3 1.6 2.3 3.1 2.3-1.1.9-2.5 1.4-4.1 1.4H0c1.5.9 3.2 1.5 5 1.5 6 0 9.3-5 9.3-9.3v-.4C15 4.3 15.6 3.7 16 3z"/></symbol><symbol id="icon-vimeo" viewBox="0 0 16 16"><path d="M16 4.3c-.1 1.6-1.2 3.7-3.3 6.4-2.2 2.8-4 4.2-5.5 4.2-.9 0-1.7-.9-2.4-2.6C4 9.9 3.4 5 2 5c-.1 0-.5.3-1.2.8l-.8-1c.8-.7 3.5-3.4 4.7-3.5 1.2-.1 2 .7 2.3 2.5.3 2 .8 6.1 1.8 6.1.9 0 2.5-3.4 2.6-4 .1-.9-.3-1.9-2.3-1.1.8-2.6 2.3-3.8 4.5-3.8 1.7.1 2.5 1.2 2.4 3.3z"/></symbol><symbol id="icon-youtube" viewBox="0 0 16 16"><path d="M15.8 4.8c-.2-1.3-.8-2.2-2.2-2.4C11.4 2 8 2 8 2s-3.4 0-5.6.4C1 2.6.3 3.5.2 4.8 0 6.1 0 8 0 8s0 1.9.2 3.2c.2 1.3.8 2.2 2.2 2.4C4.6 14 8 14 8 14s3.4 0 5.6-.4c1.4-.3 2-1.1 2.2-2.4C16 9.9 16 8 16 8s0-1.9-.2-3.2zM6 11V5l5 3-5 3z"/></symbol></svg> \ No newline at end of file
diff --git a/demo/error.html b/demo/error.html
new file mode 100644
index 00000000..f867c915
--- /dev/null
+++ b/demo/error.html
@@ -0,0 +1,18 @@
+<!doctype html>
+<html lang="en" class="error">
+ <head>
+ <meta charset="utf-8" />
+ <title>Doh. Looks like something went wrong.</title>
+ <meta name="viewport" content="width=device-width, initial-scale=1">
+
+ <!-- Docs styles -->
+ <link rel="stylesheet" href="dist/docs.css">
+ </head>
+ <body>
+ <main>
+ <h1>Doh.</h1>
+ <p>Looks like something went wrong.</p>
+ <a href="http://plyr.io" class="btn btn--primary">Back to plyr.io</a>
+ </main>
+ </body>
+</html>
diff --git a/demo/index.html b/demo/index.html
new file mode 100644
index 00000000..0c9b83af
--- /dev/null
+++ b/demo/index.html
@@ -0,0 +1,88 @@
+<!doctype html>
+<html lang="en">
+ <head>
+ <meta charset="utf-8" />
+ <title>Plyr - A simple HTML5 media player</title>
+ <meta name="description" content="A simple HTML5 media player with custom controls and WebVTT captions.">
+ <meta name="author" content="Sam Potts">
+ <meta name="viewport" content="width=device-width, initial-scale=1">
+
+ <!-- Styles -->
+ <link rel="stylesheet" href="../dist/plyr.css">
+
+ <!-- Docs styles -->
+ <link rel="stylesheet" href="dist/demo.css">
+ </head>
+ <body>
+ <header>
+ <h1>Plyr</h1>
+ <p>A simple, accessible HTML5 media player by <a href="https://twitter.com/sam_potts" target="_blank">@sam_potts</a> from <a href="https://twitter.com/selz" target="_blank">@selz</a></p>
+ <nav>
+ <ul>
+ <li>
+ <a href="https://github.com/selz/plyr" target="_blank" class="btn btn--large btn--primary" data-shr-network="github">
+ <svg class="icon"><use xlink:href="#icon-github"/></svg>Download on GitHub
+ </a>
+ </li>
+ <li>
+ <a href="https://twitter.com/intent/tweet?text=A+simple+HTML5+media+player+with+custom+controls+and+WebVTT+captions.&url=http%3A%2F%2Fplyr.io&via=Sam_Potts" target="_blank" class="btn btn--large btn--twitter" data-shr-network="twitter">
+ <svg class="icon"><use xlink:href="#icon-twitter"/></svg>Tweet
+ </a>
+ </li>
+ </ul>
+ </nav>
+ </header>
+
+ <main role="main" id="main">
+ <nav class="btn__bar">
+ <ul>
+ <li class="active">
+ <button type="button" class="btn" data-source="video">Video</button>
+ </li>
+ <li>
+ <button type="button" class="btn" data-source="audio">Audio</button>
+ </li>
+ <li>
+ <button type="button" class="btn btn--youtube" data-source="youtube"><svg class="icon"><use xlink:href="#icon-youtube"/></svg>YouTube</button>
+ </li>
+ <li>
+ <button type="button" class="btn btn--vimeo" data-source="vimeo"><svg class="icon"><use xlink:href="#icon-vimeo"/></svg>Vimeo</button>
+ </li>
+ </ul>
+ </nav>
+ <section>
+ <video poster="https://cdn.selz.com/plyr/1.5/View_From_A_Blue_Moon_Trailer-HD.jpg" controls crossorigin>
+ <!-- Video files -->
+ <source src="https://cdn.selz.com/plyr/1.5/View_From_A_Blue_Moon_Trailer-HD.mp4" type="video/mp4">
+ <source src="https://cdn.selz.com/plyr/1.5/View_From_A_Blue_Moon_Trailer-HD.webm" type="video/webm">
+
+ <!-- Text track file -->
+ <track kind="captions" label="English" srclang="en" src="https://cdn.selz.com/plyr/1.5/View_From_A_Blue_Moon_Trailer-HD.en.vtt" default>
+
+ <!-- Fallback for browsers that don't support the <video> element -->
+ <a href="https://cdn.selz.com/plyr/1.5/View_From_A_Blue_Moon_Trailer-HD.mp4" download>Download</a>
+ </video>
+
+ <ul>
+ <li class="plyr__cite plyr__cite--video"><small><a href="http://viewfromabluemoon.com/" target="_blank">View From A Blue Moon</a> &copy; Brainfarm</small></li>
+ <li class="plyr__cite plyr__cite--audio"><small><a href="http://www.kishibashi.com/" target="_blank">Kishi Bashi &ndash; &ldquo;It All Began With A Burst&rdquo;</a> &copy; Kishi Bashi</small></li>
+ <li class="plyr__cite plyr__cite--youtube"><small><a href="https://www.youtube.com/watch?v=bTqVqk7FSmY" target="_blank">View From A Blue Moon</a> on <span class="color--youtube"><svg class="icon"><use xlink:href="#icon-youtube"/></svg>YouTube</span></small>
+ <li class="plyr__cite plyr__cite--vimeo"><small><a href="https://vimeo.com/ondemand/viewfromabluemoon4k" target="_blank">View From A Blue Moon</a> on <span class="color--vimeo"><svg class="icon"><use xlink:href="#icon-vimeo"/></svg>Vimeo</span></small>
+ </ul>
+ </section>
+ </main>
+
+ <!-- Plyr core script -->
+ <script src="../dist/plyr.js"></script>
+
+ <!-- Docs script -->
+ <script src="dist/demo.js"></script>
+
+ <!-- Rangetouch to fix <input type="range"> on touch devices (see https://rangetouch.com) -->
+ <script src="https://cdn.rangetouch.com/0.0.9/rangetouch.js" async></script>
+
+ <!-- Sharing libary (https://shr.one) -->
+ <script src="https://cdn.shr.one/0.1.9/shr.js"></script>
+ <script>if(window.shr) { window.shr.setup({ count: { classname: 'btn__count' } }); }</script>
+ </body>
+</html>
diff --git a/demo/src/js/lib/classlist.js b/demo/src/js/lib/classlist.js
new file mode 100644
index 00000000..eac1e99e
--- /dev/null
+++ b/demo/src/js/lib/classlist.js
@@ -0,0 +1,237 @@
+/*
+ * classList.js: Cross-browser full element.classList implementation.
+ * 1.1.20150312
+ *
+ * By Eli Grey, http://eligrey.com
+ * License: Dedicated to the public domain.
+ * See https://github.com/eligrey/classList.js/blob/master/LICENSE.md
+ */
+
+/*global self, document, DOMException */
+
+/*! @source http://purl.eligrey.com/github/classList.js/blob/master/classList.js */
+
+if ("document" in self) {
+
+// Full polyfill for browsers with no classList support
+if (!("classList" in document.createElement("_"))) {
+
+(function (view) {
+
+"use strict";
+
+if (!('Element' in view)) return;
+
+var
+ classListProp = "classList"
+ , protoProp = "prototype"
+ , elemCtrProto = view.Element[protoProp]
+ , objCtr = Object
+ , strTrim = String[protoProp].trim || function () {
+ return this.replace(/^\s+|\s+$/g, "");
+ }
+ , arrIndexOf = Array[protoProp].indexOf || function (item) {
+ var
+ i = 0
+ , len = this.length
+ ;
+ for (; i < len; i++) {
+ if (i in this && this[i] === item) {
+ return i;
+ }
+ }
+ return -1;
+ }
+ // Vendors: please allow content code to instantiate DOMExceptions
+ , DOMEx = function (type, message) {
+ this.name = type;
+ this.code = DOMException[type];
+ this.message = message;
+ }
+ , checkTokenAndGetIndex = function (classList, token) {
+ if (token === "") {
+ throw new DOMEx(
+ "SYNTAX_ERR"
+ , "An invalid or illegal string was specified"
+ );
+ }
+ if (/\s/.test(token)) {
+ throw new DOMEx(
+ "INVALID_CHARACTER_ERR"
+ , "String contains an invalid character"
+ );
+ }
+ return arrIndexOf.call(classList, token);
+ }
+ , ClassList = function (elem) {
+ var
+ trimmedClasses = strTrim.call(elem.getAttribute("class") || "")
+ , classes = trimmedClasses ? trimmedClasses.split(/\s+/) : []
+ , i = 0
+ , len = classes.length
+ ;
+ for (; i < len; i++) {
+ this.push(classes[i]);
+ }
+ this._updateClassName = function () {
+ elem.setAttribute("class", this.toString());
+ };
+ }
+ , classListProto = ClassList[protoProp] = []
+ , classListGetter = function () {
+ return new ClassList(this);
+ }
+;
+// Most DOMException implementations don't allow calling DOMException's toString()
+// on non-DOMExceptions. Error's toString() is sufficient here.
+DOMEx[protoProp] = Error[protoProp];
+classListProto.item = function (i) {
+ return this[i] || null;
+};
+classListProto.contains = function (token) {
+ token += "";
+ return checkTokenAndGetIndex(this, token) !== -1;
+};
+classListProto.add = function () {
+ var
+ tokens = arguments
+ , i = 0
+ , l = tokens.length
+ , token
+ , updated = false
+ ;
+ do {
+ token = tokens[i] + "";
+ if (checkTokenAndGetIndex(this, token) === -1) {
+ this.push(token);
+ updated = true;
+ }
+ }
+ while (++i < l);
+
+ if (updated) {
+ this._updateClassName();
+ }
+};
+classListProto.remove = function () {
+ var
+ tokens = arguments
+ , i = 0
+ , l = tokens.length
+ , token
+ , updated = false
+ , index
+ ;
+ do {
+ token = tokens[i] + "";
+ index = checkTokenAndGetIndex(this, token);
+ while (index !== -1) {
+ this.splice(index, 1);
+ updated = true;
+ index = checkTokenAndGetIndex(this, token);
+ }
+ }
+ while (++i < l);
+
+ if (updated) {
+ this._updateClassName();
+ }
+};
+classListProto.toggle = function (token, force) {
+ token += "";
+
+ var
+ result = this.contains(token)
+ , method = result ?
+ force !== true && "remove"
+ :
+ force !== false && "add"
+ ;
+
+ if (method) {
+ this[method](token);
+ }
+
+ if (force === true || force === false) {
+ return force;
+ } else {
+ return !result;
+ }
+};
+classListProto.toString = function () {
+ return this.join(" ");
+};
+
+if (objCtr.defineProperty) {
+ var classListPropDesc = {
+ get: classListGetter
+ , enumerable: true
+ , configurable: true
+ };
+ try {
+ objCtr.defineProperty(elemCtrProto, classListProp, classListPropDesc);
+ } catch (ex) { // IE 8 doesn't support enumerable:true
+ if (ex.number === -0x7FF5EC54) {
+ classListPropDesc.enumerable = false;
+ objCtr.defineProperty(elemCtrProto, classListProp, classListPropDesc);
+ }
+ }
+} else if (objCtr[protoProp].__defineGetter__) {
+ elemCtrProto.__defineGetter__(classListProp, classListGetter);
+}
+
+}(self));
+
+} else {
+// There is full or partial native classList support, so just check if we need
+// to normalize the add/remove and toggle APIs.
+
+(function () {
+ "use strict";
+
+ var testElement = document.createElement("_");
+
+ testElement.classList.add("c1", "c2");
+
+ // Polyfill for IE 10/11 and Firefox <26, where classList.add and
+ // classList.remove exist but support only one argument at a time.
+ if (!testElement.classList.contains("c2")) {
+ var createMethod = function(method) {
+ var original = DOMTokenList.prototype[method];
+
+ DOMTokenList.prototype[method] = function(token) {
+ var i, len = arguments.length;
+
+ for (i = 0; i < len; i++) {
+ token = arguments[i];
+ original.call(this, token);
+ }
+ };
+ };
+ createMethod('add');
+ createMethod('remove');
+ }
+
+ testElement.classList.toggle("c3", false);
+
+ // Polyfill for IE 10 and Firefox <24, where classList.toggle does not
+ // support the second argument.
+ if (testElement.classList.contains("c3")) {
+ var _toggle = DOMTokenList.prototype.toggle;
+
+ DOMTokenList.prototype.toggle = function(token, force) {
+ if (1 in arguments && !this.contains(token) === !force) {
+ return force;
+ } else {
+ return _toggle.call(this, token);
+ }
+ };
+
+ }
+
+ testElement = null;
+}());
+
+}
+
+} \ No newline at end of file
diff --git a/demo/src/js/main.js b/demo/src/js/main.js
new file mode 100644
index 00000000..bdd7febe
--- /dev/null
+++ b/demo/src/js/main.js
@@ -0,0 +1,185 @@
+// ==========================================================================
+// Plyr.io demo
+// This code is purely for the plyr.io website
+// Please see readme.md in the root or github.com/selz/plyr
+// ==========================================================================
+
+/*global plyr*/
+
+// General functions
+;(function() {
+ document.body.addEventListener('ready', function(event) { console.log(event); });
+
+ // Setup the player
+ var instances = plyr.setup({
+ debug: true,
+ title: 'Video demo',
+ iconUrl: '../dist/plyr.svg',
+ tooltips: {
+ controls: true
+ },
+ captions: {
+ defaultActive: true
+ }
+ });
+ plyr.loadSprite('dist/demo.svg');
+
+ // Plyr returns an array regardless
+ var player = instances[0].plyr;
+
+ // Setup type toggle
+ var buttons = document.querySelectorAll('[data-source]'),
+ types = {
+ video: 'video',
+ audio: 'audio',
+ youtube: 'youtube',
+ vimeo: 'vimeo'
+ },
+ currentType = window.location.hash.replace('#', ''),
+ historySupport = (window.history && window.history.pushState);
+
+ // Bind to each button
+ for (var i = buttons.length - 1; i >= 0; i--) {
+ buttons[i].addEventListener('click', function() {
+ var type = this.getAttribute('data-source');
+
+ newSource(type);
+
+ if (historySupport) {
+ history.pushState({ 'type': type }, '', '#' + type);
+ }
+ });
+ }
+
+ // List for backwards/forwards
+ window.addEventListener('popstate', function(event) {
+ if(event.state && 'type' in event.state) {
+ newSource(event.state.type);
+ }
+ });
+
+ // On load
+ if(historySupport) {
+ var video = !currentType.length;
+
+ // If there's no current type set, assume video
+ if(video) {
+ currentType = types.video;
+ }
+
+ // Replace current history state
+ if(currentType in types) {
+ history.replaceState({ 'type': currentType }, '', (video ? '' : '#' + currentType));
+ }
+
+ // If it's not video, load the source
+ if(currentType !== types.video) {
+ newSource(currentType, true);
+ }
+ }
+
+ // Toggle class on an element
+ function toggleClass(element, className, state) {
+ if (element) {
+ if (element.classList) {
+ element.classList[state ? 'add' : 'remove'](className);
+ }
+ else {
+ var name = (' ' + element.className + ' ').replace(/\s+/g, ' ').replace(' ' + className + ' ', '');
+ element.className = name + (state ? ' ' + className : '');
+ }
+ }
+ }
+
+ // Set a new source
+ function newSource(type, init) {
+ // Bail if new type isn't known, it's the current type, or current type is empty (video is default) and new type is video
+ if(!(type in types) || (!init && type == currentType) || (!currentType.length && type == types.video)) {
+ return;
+ }
+
+ switch(type) {
+ case types.video:
+ player.source({
+ type: 'video',
+ title: 'View From A Blue Moon',
+ sources: [{
+ src: 'https://cdn.selz.com/plyr/1.5/View_From_A_Blue_Moon_Trailer-HD.mp4',
+ type: 'video/mp4'
+ },
+ {
+ src: 'https://cdn.selz.com/plyr/1.5/View_From_A_Blue_Moon_Trailer-HD.webm',
+ type: 'video/webm'
+ }],
+ poster: 'https://cdn.selz.com/plyr/1.5/View_From_A_Blue_Moon_Trailer-HD.jpg',
+ tracks: [{
+ kind: 'captions',
+ label: 'English',
+ srclang:'en',
+ src: 'https://cdn.selz.com/plyr/1.5/View_From_A_Blue_Moon_Trailer-HD.en.vtt',
+ default: true
+ }]
+ });
+ break;
+
+ case types.audio:
+ player.source({
+ type: 'audio',
+ title: 'Kishi Bashi &ndash; &ldquo;It All Began With A Burst&rdquo;',
+ sources: [{
+ src: 'https://cdn.selz.com/plyr/1.5/Kishi_Bashi_-_It_All_Began_With_a_Burst.mp3',
+ type: 'audio/mp3'
+ },
+ {
+ src: 'https://cdn.selz.com/plyr/1.5/Kishi_Bashi_-_It_All_Began_With_a_Burst.ogg',
+ type: 'audio/ogg'
+ }]
+ });
+ break;
+
+ case types.youtube:
+ player.source({
+ type: 'video',
+ title: 'View From A Blue Moon',
+ sources: [{
+ src: 'bTqVqk7FSmY',
+ type: 'youtube'
+ }]
+ });
+ break;
+
+ case types.vimeo:
+ player.source({
+ type: 'video',
+ title: 'View From A Blue Moon',
+ sources: [{
+ src: '143418951',
+ type: 'vimeo'
+ }]
+ });
+ break;
+ }
+
+ // Set the current type for next time
+ currentType = type;
+
+ // Remove active classes
+ for (var x = buttons.length - 1; x >= 0; x--) {
+ toggleClass(buttons[x].parentElement, 'active', false);
+ }
+
+ // Set active on parent
+ toggleClass(document.querySelector('[data-source="'+ type +'"]').parentElement, 'active', true);
+ }
+})();
+
+// Google analytics
+// For demo site (http://[www.]plyr.io) only
+if(document.domain.indexOf('plyr.io') > -1) {
+ (function(i,s,o,g,r,a,m){i.GoogleAnalyticsObject=r;i[r]=i[r]||function(){
+ (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
+ m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
+ })(window,document,'script','//www.google-analytics.com/analytics.js','ga');
+ ga('create', 'UA-40881672-11', 'auto');
+ ga('send', 'pageview');
+}
diff --git a/demo/src/less/components/base.less b/demo/src/less/components/base.less
new file mode 100644
index 00000000..c584b57e
--- /dev/null
+++ b/demo/src/less/components/base.less
@@ -0,0 +1,47 @@
+// ==========================================================================
+// Base layout
+// ==========================================================================
+
+// BORDER-BOX ALL THE THINGS!
+// http://paulirish.com/2012/box-sizing-border-box-ftw/
+*, *::after, *::before {
+ box-sizing: border-box;
+}
+
+// Hidden
+[hidden] {
+ display: none;
+}
+
+// Base
+html {
+ height: 100%;
+ background: @body-background fixed;
+}
+body {
+ margin: 0;
+ padding: (@padding-base / 2);
+}
+
+// Header
+header {
+ padding: @padding-base;
+ margin-bottom: @padding-base;
+
+ p {
+ .font-size(18);
+ }
+ @media (min-width: @screen-sm) {
+ padding-top: (@padding-base * 3);
+ padding-bottom: (@padding-base * 3);
+ }
+}
+
+// Sections
+section {
+ padding-bottom: @padding-base;
+
+ @media (min-width: @screen-sm) {
+ padding-bottom: (@padding-base * 2);
+ }
+} \ No newline at end of file
diff --git a/demo/src/less/components/buttons.less b/demo/src/less/components/buttons.less
new file mode 100644
index 00000000..c99a0836
--- /dev/null
+++ b/demo/src/less/components/buttons.less
@@ -0,0 +1,172 @@
+// ==========================================================================
+// Buttons
+// ==========================================================================
+
+nav {
+ ul {
+ list-style: none;
+ margin: 0;
+ padding: 0;
+ font-size: 0;
+ }
+ li {
+ display: inline-block;
+ margin-top: (@padding-base / 2);
+ .font-size();
+ white-space: nowrap;
+ }
+ li + li {
+ margin-left: @padding-base;
+ }
+}
+
+// Tabs
+.btn__bar {
+ position: relative;
+ margin: 0 auto @padding-base;
+ max-width: @example-width-video;
+ white-space: nowrap;
+
+ &::before {
+ content: "";
+ position: absolute;
+ top: 50%;
+ left: 0;
+ right: 0;
+ height: 1px;
+ background: @gray-lighter;
+ }
+
+ ul {
+ position: relative;
+ z-index: 1;
+ display: inline-block;
+ user-select: none;
+ }
+ li {
+ margin: 0;
+
+ &:first-child .btn {
+ border-radius: 4px 0 0 4px;
+ }
+ &:last-child .btn {
+ border-radius: 0 4px 4px 0;
+ }
+ & + li .btn {
+ margin-left: -1px;
+ }
+
+ &.active .btn {
+ &:extend(.btn--primary);
+ box-shadow: inset 0 1px 1px rgba(0,0,0, .2);
+ position: relative;
+ z-index: 1;
+
+ .icon {
+ color: inherit;
+ }
+ }
+ &.active + li .btn:hover {
+ z-index: 0;
+ }
+ }
+ .btn {
+ position: relative;
+ display: block;
+ border-radius: 0;
+
+ &:hover,
+ &:focus {
+ z-index: 1;
+ }
+ }
+
+ @media (min-width: 560px) {
+ margin-bottom: (@padding-base * 2);
+ }
+}
+
+// Shared
+.btn,
+.btn__count {
+ display: inline-block;
+ vertical-align: middle;
+ border-radius: @border-radius-base;
+ user-select: none;
+ font-weight: @font-weight-bold;
+}
+
+// Buttons
+.btn {
+ padding: (@padding-base / 2) ((@padding-base / 2) + 2);
+ background: linear-gradient(lighten(@off-white, 2%), darken(@off-white, 3%));
+ border: 1px solid @gray-light;
+ box-shadow: 0 1px 1px rgba(0,0,0, .05);
+ text-shadow: 0 1px 1px #fff;
+ color: @gray;
+ transition: background .1s ease, color .1s ease;
+ .font-size(@font-size-small);
+
+ &:hover,
+ &:focus {
+ border-color: darken(@gray-light, 8%);
+ color: @gray;
+ outline: 0;
+ }
+}
+
+// Sizes
+.btn--large {
+ padding: (@padding-base / 2) @padding-base;
+ .font-size();
+}
+
+// Styles
+.btn--primary {
+ background-image: linear-gradient(@link-color, darken(@link-color, 5%));
+ background-color: @link-color;
+ border-color: darken(@link-color, 10%);
+ box-shadow: 0 1px 1px rgba(0,0,0, .15);
+ text-shadow: 0 1px 1px rgba(0,0,0, .1);
+ color: #fff;
+
+ &:hover,
+ &:focus {
+ color: #fff;
+ border-color: darken(@link-color, 20%);
+ }
+}
+.btn--youtube .icon {
+ color: @color-youtube;
+}
+.btn--vimeo .icon {
+ color: @color-vimeo;
+}
+.btn--twitter .icon {
+ color: @color-twitter;
+}
+
+// Count bubble
+.btn__count {
+ position: relative;
+ margin-left: (@padding-base / 2);
+ padding: (@padding-base / 2) (@padding-base * .75);
+ background: #fff;
+ border: 1px solid @gray-light;
+
+ &::before {
+ content: "";
+ position: absolute;
+ display: block;
+ width: @arrow-size;
+ height: @arrow-size;
+ left: 1px;
+ top: 50%;
+ margin-top: -(@arrow-size / 2);
+
+ background: inherit;
+ border: inherit;
+ border-width: 1px 0 0 1px;
+ transform: rotate(-45deg) translate(-50%, -50%);
+ }
+}
diff --git a/demo/src/less/components/error.less b/demo/src/less/components/error.less
new file mode 100644
index 00000000..b1427173
--- /dev/null
+++ b/demo/src/less/components/error.less
@@ -0,0 +1,19 @@
+// ==========================================================================
+// Errors (AWS pages)
+// ==========================================================================
+
+// Error page
+html.error,
+.error body {
+ height: 100%;
+}
+.error body {
+ width: 100%;
+ display: table;
+ table-layout: fixed;
+}
+.error main {
+ display: table-cell;
+ width: 100%;
+ vertical-align: middle;
+} \ No newline at end of file
diff --git a/demo/src/less/components/examples.less b/demo/src/less/components/examples.less
new file mode 100644
index 00000000..8649c023
--- /dev/null
+++ b/demo/src/less/components/examples.less
@@ -0,0 +1,51 @@
+// ==========================================================================
+// Examples
+// ==========================================================================
+
+section {
+ margin: 0 auto @padding-base;
+ max-width: @example-width-video;
+}
+
+// For non supported browsers
+video {
+ max-width: 100%;
+ vertical-align: middle;
+}
+
+// Example players
+.plyr {
+ margin: 0 auto;
+ border-radius: @border-radius-large;
+}
+.plyr--audio {
+ max-width: @example-width-audio;
+}
+.plyr__video-wrapper::after {
+ content: "";
+ pointer-events: none;
+ position: absolute;
+ top: 0;
+ bottom: 0;
+ left: 0;
+ right: 0;
+ border: 1px solid fade(#000, 15%);
+ border-radius: inherit;
+}
+
+// Style full supported player
+.plyr__cite {
+ display: none;
+ margin-top: @padding-base;
+
+ .icon {
+ margin-right: (@padding-base / 4);
+ }
+}
+
+.plyr--video:not(.plyr--youtube):not(.plyr--vimeo) ~ ul .plyr__cite--video,
+.plyr--audio ~ ul .plyr__cite--audio,
+.plyr--youtube ~ ul .plyr__cite--youtube,
+.plyr--vimeo ~ ul .plyr__cite--vimeo {
+ display: block;
+}
diff --git a/demo/src/less/components/icons.less b/demo/src/less/components/icons.less
new file mode 100644
index 00000000..9530b601
--- /dev/null
+++ b/demo/src/less/components/icons.less
@@ -0,0 +1,26 @@
+// ==========================================================================
+// Icons
+// ==========================================================================
+
+// Base size icon styles
+.icon {
+ fill: currentColor;
+ width: @icon-size;
+ height: @icon-size;
+ vertical-align: -3px;
+}
+
+// Within elements
+a svg,
+button svg,
+label svg {
+ pointer-events: none;
+}
+a .icon,
+.btn .icon {
+ margin-right: (@padding-base / 2);
+}
+.btn:not(.btn-large) .icon {
+ width: (@icon-size - 2);
+ height: (@icon-size - 2);
+}
diff --git a/demo/src/less/components/type.less b/demo/src/less/components/type.less
new file mode 100644
index 00000000..951be36d
--- /dev/null
+++ b/demo/src/less/components/type.less
@@ -0,0 +1,75 @@
+// ==========================================================================
+// Typography
+// ==========================================================================
+
+// Base
+html {
+ font-size: 100%;
+}
+body {
+ font-family: "Avenir", "Helvetica Neue", Helvetica, Arial, sans-serif;
+ line-height: 1.5;
+ text-align: center;
+ color: @gray;
+ font-weight: @font-weight-base;
+ .font-smoothing();
+}
+
+// Headings
+h1,
+h2 {
+ letter-spacing: -.025em;
+ color: @brand-primary;
+ margin: 0 0 (@padding-base / 2);
+ line-height: 1.2;
+ font-weight: @font-weight-bold;
+}
+h1 {
+ .font-size(@font-size-h1);
+}
+
+// Paragraph and small
+p,
+small {
+ margin: 0 0 @padding-base;
+}
+small {
+ display: block;
+ padding: 0 (@padding-base / 2);
+ .font-size(@font-size-small);
+}
+
+// Lists
+ul,
+li {
+ list-style: none;
+ margin: 0;
+ padding: 0;
+}
+
+// Links
+a {
+ text-decoration: none;
+ color: @link-color;
+ border-bottom: 1px dotted currentColor;
+ transition: background .3s ease, color .3s ease, border .3s ease;
+
+ &:hover,
+ &:focus {
+ color: @gray-dark;
+ border-bottom-color: rgba(0,0,0,0);
+ }
+ &:focus {
+ .tab-focus();
+ }
+ &.logo {
+ border: 0;
+ }
+}
+
+.color--vimeo {
+ color: @color-vimeo;
+}
+.color--youtube {
+ color: @color-youtube;
+}
diff --git a/demo/src/less/demo.less b/demo/src/less/demo.less
new file mode 100644
index 00000000..ac15a3c0
--- /dev/null
+++ b/demo/src/less/demo.less
@@ -0,0 +1,26 @@
+// ==========================================================================
+// Plyr.io Demo Page
+// ==========================================================================
+
+// CSS Reset
+@import "lib/normalize.less";
+
+// Mixins
+@import "lib/mixins.less";
+
+// Variables
+@import "variables.less";
+
+// Animation
+@import "lib/animation.less";
+
+// Type
+@import "lib/fontface.less";
+@import "components/type.less";
+
+// Components
+@import "components/base.less";
+@import "components/icons.less";
+@import "components/buttons.less";
+@import "components/error.less";
+@import "components/examples.less";
diff --git a/demo/src/less/lib/animation.less b/demo/src/less/lib/animation.less
new file mode 100644
index 00000000..386c6613
--- /dev/null
+++ b/demo/src/less/lib/animation.less
@@ -0,0 +1,9 @@
+// ==========================================================================
+// Animations
+// ==========================================================================
+
+// Fade
+@keyframes fade-in {
+ 0% { opacity: 0 }
+ 100% { opacity: 1 }
+} \ No newline at end of file
diff --git a/demo/src/less/lib/fontface.less b/demo/src/less/lib/fontface.less
new file mode 100644
index 00000000..a7da5ad9
--- /dev/null
+++ b/demo/src/less/lib/fontface.less
@@ -0,0 +1,18 @@
+// ==========================================================================
+// Fonts
+// ==========================================================================
+
+@font-face {
+ font-family: "Avenir";
+ src: url("//cdn.plyr.io/fonts/avenir-medium.woff2") format("woff2"),
+ url("//cdn.plyr.io/fonts/avenir-medium.woff") format("woff");
+ font-style: normal;
+ font-weight: @font-weight-base;
+}
+@font-face {
+ font-family: "Avenir";
+ src: url("//cdn.plyr.io/fonts/avenir-bold.woff2") format("woff2"),
+ url("//cdn.plyr.io/fonts/avenir-bold.woff") format("woff");
+ font-style: normal;
+ font-weight: @font-weight-bold;
+} \ No newline at end of file
diff --git a/demo/src/less/lib/mixins.less b/demo/src/less/lib/mixins.less
new file mode 100644
index 00000000..923df1ea
--- /dev/null
+++ b/demo/src/less/lib/mixins.less
@@ -0,0 +1,41 @@
+// ==========================================================================
+// Mixins
+// ==========================================================================
+
+// Contain floats: nicolasgallagher.com/micro-clearfix-hack/
+// ---------------------------------------
+.clearfix() {
+ zoom: 1;
+ &:before,
+ &:after { content: ""; display: table; }
+ &:after { clear: both; }
+}
+
+// Webkit-style focus
+// ---------------------------------------
+.tab-focus() {
+ // Default
+ outline: thin dotted @gray-dark;
+ // Webkit
+ outline-offset: 1px;
+}
+
+// Use rems for font sizing
+// Leave <body> at 100%/16px
+// ---------------------------------------
+.font-size(@font-size: 16){
+ @rem: round((@font-size / 16), 3);
+ font-size: (@font-size * 1px);
+ font-size: ~"@{rem}rem";
+}
+
+// Font smoothing
+// ---------------------------------------
+.font-smoothing(@mode: on) when (@mode = on) {
+ -moz-osx-font-smoothing: grayscale;
+ -webkit-font-smoothing: antialiased;
+}
+.font-smoothing(@mode: on) when (@mode = off) {
+ -moz-osx-font-smoothing: auto;
+ -webkit-font-smoothing: subpixel-antialiased;
+} \ No newline at end of file
diff --git a/demo/src/less/lib/normalize.less b/demo/src/less/lib/normalize.less
new file mode 100644
index 00000000..562891ab
--- /dev/null
+++ b/demo/src/less/lib/normalize.less
@@ -0,0 +1,406 @@
+/*! normalize.css v2.1.3 | MIT License | git.io/normalize */
+
+/* ==========================================================================
+ HTML5 display definitions
+ ========================================================================== */
+
+/**
+ * Correct `block` display not defined in IE 8/9.
+ */
+
+article,
+aside,
+details,
+figcaption,
+figure,
+footer,
+header,
+hgroup,
+main,
+nav,
+section,
+summary {
+ display: block;
+}
+
+/**
+ * Correct `inline-block` display not defined in IE 8/9.
+ */
+
+audio,
+canvas,
+video {
+ display: inline-block;
+}
+
+/**
+ * Prevent modern browsers from displaying `audio` without controls.
+ * Remove excess height in iOS 5 devices.
+ */
+
+audio:not([controls]) {
+ display: none;
+ height: 0;
+}
+
+/**
+ * Address `[hidden]` styling not present in IE 8/9.
+ * Hide the `template` element in IE, Safari, and Firefox < 22.
+ */
+
+[hidden],
+template {
+ display: none;
+}
+
+/* ==========================================================================
+ Base
+ ========================================================================== */
+
+/**
+ * 1. Set default font family to sans-serif.
+ * 2. Prevent iOS text size adjust after orientation change, without disabling
+ * user zoom.
+ */
+
+html {
+ font-family: sans-serif; /* 1 */
+ -ms-text-size-adjust: 100%; /* 2 */
+ -webkit-text-size-adjust: 100%; /* 2 */
+}
+
+/**
+ * Remove default margin.
+ */
+
+body {
+ margin: 0;
+}
+
+/* ==========================================================================
+ Links
+ ========================================================================== */
+
+/**
+ * Remove the gray background color from active links in IE 10.
+ */
+
+a {
+ background: transparent;
+}
+
+/**
+ * Address `outline` inconsistency between Chrome and other browsers.
+ */
+
+a:focus {
+ outline: thin dotted;
+}
+
+/**
+ * Improve readability when focused and also mouse hovered in all browsers.
+ */
+
+a:active,
+a:hover {
+ outline: 0;
+}
+
+/* ==========================================================================
+ Typography
+ ========================================================================== */
+
+/**
+ * Address variable `h1` font-size and margin within `section` and `article`
+ * contexts in Firefox 4+, Safari 5, and Chrome.
+ */
+
+h1 {
+ font-size: 2em;
+ margin: 0.67em 0;
+}
+
+/**
+ * Address styling not present in IE 8/9, Safari 5, and Chrome.
+ */
+
+abbr[title] {
+ border-bottom: 1px dotted;
+}
+
+/**
+ * Address style set to `bolder` in Firefox 4+, Safari 5, and Chrome.
+ */
+
+b,
+strong {
+ font-weight: bold;
+}
+
+/**
+ * Address styling not present in Safari 5 and Chrome.
+ */
+
+dfn {
+ font-style: italic;
+}
+
+/**
+ * Address differences between Firefox and other browsers.
+ */
+
+hr {
+ -moz-box-sizing: content-box;
+ box-sizing: content-box;
+ height: 0;
+}
+
+/**
+ * Address styling not present in IE 8/9.
+ */
+
+mark {
+ background: #ff0;
+ color: #000;
+}
+
+/**
+ * Correct font family set oddly in Safari 5 and Chrome.
+ */
+
+code,
+kbd,
+pre,
+samp {
+ font-family: monospace, serif;
+ font-size: 1em;
+}
+
+/**
+ * Improve readability of pre-formatted text in all browsers.
+ */
+
+pre {
+ white-space: pre-wrap;
+}
+
+/**
+ * Set consistent quote types.
+ */
+
+q {
+ quotes: "\201C" "\201D" "\2018" "\2019";
+}
+
+/**
+ * Address inconsistent and variable font size in all browsers.
+ */
+
+small {
+ font-size: 80%;
+}
+
+/**
+ * Prevent `sub` and `sup` affecting `line-height` in all browsers.
+ */
+
+sub,
+sup {
+ font-size: 75%;
+ line-height: 0;
+ position: relative;
+ vertical-align: baseline;
+}
+
+sup {
+ top: -0.5em;
+}
+
+sub {
+ bottom: -0.25em;
+}
+
+/* ==========================================================================
+ Embedded content
+ ========================================================================== */
+
+/**
+ * Remove border when inside `a` element in IE 8/9.
+ */
+
+img {
+ border: 0;
+}
+
+/**
+ * Correct overflow displayed oddly in IE 9.
+ */
+
+svg:not(:root) {
+ overflow: hidden;
+}
+
+/* ==========================================================================
+ Figures
+ ========================================================================== */
+
+/**
+ * Address margin not present in IE 8/9 and Safari 5.
+ */
+
+figure {
+ margin: 0;
+}
+
+/* ==========================================================================
+ Forms
+ ========================================================================== */
+
+/**
+ * Define consistent border, margin, and padding.
+ */
+
+fieldset {
+ border: 1px solid #c0c0c0;
+ margin: 0 2px;
+ padding: 0.35em 0.625em 0.75em;
+}
+
+/**
+ * 1. Correct `color` not being inherited in IE 8/9.
+ * 2. Remove padding so people aren't caught out if they zero out fieldsets.
+ */
+
+legend {
+ border: 0; /* 1 */
+ padding: 0; /* 2 */
+}
+
+/**
+ * 1. Correct font family not being inherited in all browsers.
+ * 2. Correct font size not being inherited in all browsers.
+ * 3. Address margins set differently in Firefox 4+, Safari 5, and Chrome.
+ */
+
+button,
+input,
+select,
+textarea {
+ font-family: inherit; /* 1 */
+ font-size: 100%; /* 2 */
+ margin: 0; /* 3 */
+}
+
+/**
+ * Address Firefox 4+ setting `line-height` on `input` using `!important` in
+ * the UA stylesheet.
+ */
+
+button,
+input {
+ line-height: normal;
+}
+
+/**
+ * Address inconsistent `text-transform` inheritance for `button` and `select`.
+ * All other form control elements do not inherit `text-transform` values.
+ * Correct `button` style inheritance in Chrome, Safari 5+, and IE 8+.
+ * Correct `select` style inheritance in Firefox 4+ and Opera.
+ */
+
+button,
+select {
+ text-transform: none;
+}
+
+/**
+ * 1. Avoid the WebKit bug in Android 4.0.* where (2) destroys native `audio`
+ * and `video` controls.
+ * 2. Correct inability to style clickable `input` types in iOS.
+ * 3. Improve usability and consistency of cursor style between image-type
+ * `input` and others.
+ */
+
+button,
+html input[type="button"], /* 1 */
+input[type="reset"],
+input[type="submit"] {
+ -webkit-appearance: button; /* 2 */
+ cursor: pointer; /* 3 */
+}
+
+/**
+ * Re-set default cursor for disabled elements.
+ */
+
+button[disabled],
+html input[disabled] {
+ cursor: default;
+}
+
+/**
+ * 1. Address box sizing set to `content-box` in IE 8/9/10.
+ * 2. Remove excess padding in IE 8/9/10.
+ */
+
+input[type="checkbox"],
+input[type="radio"] {
+ box-sizing: border-box; /* 1 */
+ padding: 0; /* 2 */
+}
+
+/**
+ * 1. Address `appearance` set to `searchfield` in Safari 5 and Chrome.
+ * 2. Address `box-sizing` set to `border-box` in Safari 5 and Chrome
+ * (include `-moz` to future-proof).
+ */
+
+input[type="search"] {
+ -webkit-appearance: textfield; /* 1 */
+ -moz-box-sizing: content-box;
+ -webkit-box-sizing: content-box; /* 2 */
+ box-sizing: content-box;
+}
+
+/**
+ * Remove inner padding and search cancel button in Safari 5 and Chrome
+ * on OS X.
+ */
+
+input[type="search"]::-webkit-search-cancel-button,
+input[type="search"]::-webkit-search-decoration {
+ -webkit-appearance: none;
+}
+
+/**
+ * Remove inner padding and border in Firefox 4+.
+ */
+
+button::-moz-focus-inner,
+input::-moz-focus-inner {
+ border: 0;
+ padding: 0;
+}
+
+/**
+ * 1. Remove default vertical scrollbar in IE 8/9.
+ * 2. Improve readability and alignment in all browsers.
+ */
+
+textarea {
+ overflow: auto; /* 1 */
+ vertical-align: top; /* 2 */
+}
+
+/* ==========================================================================
+ Tables
+ ========================================================================== */
+
+/**
+ * Remove most spacing between table cells.
+ */
+
+table {
+ border-collapse: collapse;
+ border-spacing: 0;
+} \ No newline at end of file
diff --git a/demo/src/less/variables.less b/demo/src/less/variables.less
new file mode 100644
index 00000000..4768cdd6
--- /dev/null
+++ b/demo/src/less/variables.less
@@ -0,0 +1,48 @@
+// ==========================================================================
+// Variables
+// ==========================================================================
+
+// Colors
+@gray-dark: #343f4a;
+@gray: #55646b;
+@gray-light: #cbd0d3;
+@gray-lighter: #dbe3e8;
+@off-white: #f2f5f7;
+
+@brand-primary: #3498db;
+@brand-secondary: #02BD9B;
+
+// Brands
+@color-twitter: #4BAAF4;
+@color-youtube: #cc181e;
+@color-vimeo: #19b7ed;
+
+// Base
+@body-background: @off-white; //linear-gradient(to left top, @brand-secondary, @brand-primary);
+
+// Type
+@font-size-base: 16;
+@font-size-small: 14;
+@font-size-h1: 64;
+@font-weight-base: 500;
+@font-weight-bold: 700;
+
+// Elements
+@link-color: @brand-primary;
+@padding-base: 20px;
+@arrow-size: 8px;
+
+// Icons
+@icon-size: 18px;
+
+// Breakpoints
+@screen-sm: 480px;
+@screen-md: 768px;
+
+// Radii
+@border-radius-base: 4px;
+@border-radius-large: 6px;
+
+// Examples
+@example-width-audio: 520px;
+@example-width-video: 1200px;
diff --git a/demo/src/sprite/icon-github.svg b/demo/src/sprite/icon-github.svg
new file mode 100755
index 00000000..685dd746
--- /dev/null
+++ b/demo/src/sprite/icon-github.svg
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Generator: Adobe Illustrator 19.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
+ width="16px" height="16px" viewBox="0 0 16 16" enable-background="new 0 0 16 16" xml:space="preserve">
+<path fill-rule="evenodd" clip-rule="evenodd" d="M8,0.2c-4.4,0-8,3.6-8,8c0,3.5,2.3,6.5,5.5,7.6
+ C5.9,15.9,6,15.6,6,15.4c0-0.2,0-0.7,0-1.4C3.8,14.5,3.3,13,3.3,13c-0.4-0.9-0.9-1.2-0.9-1.2c-0.7-0.5,0.1-0.5,0.1-0.5
+ c0.8,0.1,1.2,0.8,1.2,0.8C4.4,13.4,5.6,13,6,12.8c0.1-0.5,0.3-0.9,0.5-1.1c-1.8-0.2-3.6-0.9-3.6-4c0-0.9,0.3-1.6,0.8-2.1
+ c-0.1-0.2-0.4-1,0.1-2.1c0,0,0.7-0.2,2.2,0.8c0.6-0.2,1.3-0.3,2-0.3c0.7,0,1.4,0.1,2,0.3c1.5-1,2.2-0.8,2.2-0.8
+ c0.4,1.1,0.2,1.9,0.1,2.1c0.5,0.6,0.8,1.3,0.8,2.1c0,3.1-1.9,3.7-3.7,3.9C9.7,12,10,12.5,10,13.2c0,1.1,0,1.9,0,2.2
+ c0,0.2,0.1,0.5,0.6,0.4c3.2-1.1,5.5-4.1,5.5-7.6C16,3.8,12.4,0.2,8,0.2z"/>
+</svg>
diff --git a/demo/src/sprite/icon-twitter.svg b/demo/src/sprite/icon-twitter.svg
new file mode 100755
index 00000000..b3f644b1
--- /dev/null
+++ b/demo/src/sprite/icon-twitter.svg
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Generator: Adobe Illustrator 19.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
+ width="16px" height="16px" viewBox="0 0 16 16" enable-background="new 0 0 16 16" xml:space="preserve">
+ <title>Twitter</title>
+<path d="M16,3c-0.6,0.3-1.2,0.4-1.9,0.5c0.7-0.4,1.2-1,1.4-1.8c-0.6,0.4-1.3,0.6-2.1,0.8c-0.6-0.6-1.5-1-2.4-1
+ C9.3,1.5,7.8,3,7.8,4.8c0,0.3,0,0.5,0.1,0.7C5.2,5.4,2.7,4.1,1.1,2.1c-0.3,0.5-0.4,1-0.4,1.7c0,1.1,0.6,2.1,1.5,2.7
+ c-0.5,0-1-0.2-1.5-0.4c0,0,0,0,0,0c0,1.6,1.1,2.9,2.6,3.2C3,9.4,2.7,9.4,2.4,9.4c-0.2,0-0.4,0-0.6-0.1c0.4,1.3,1.6,2.3,3.1,2.3
+ c-1.1,0.9-2.5,1.4-4.1,1.4c-0.3,0-0.5,0-0.8,0c1.5,0.9,3.2,1.5,5,1.5c6,0,9.3-5,9.3-9.3c0-0.1,0-0.3,0-0.4C15,4.3,15.6,3.7,16,3z"/>
+</svg>
diff --git a/demo/src/sprite/icon-vimeo.svg b/demo/src/sprite/icon-vimeo.svg
new file mode 100755
index 00000000..83dd3dc0
--- /dev/null
+++ b/demo/src/sprite/icon-vimeo.svg
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Generator: Adobe Illustrator 19.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
+ width="16px" height="16px" viewBox="0 0 16 16" enable-background="new 0 0 16 16" xml:space="preserve">
+<path d="M16,4.3c-0.1,1.6-1.2,3.7-3.3,6.4c-2.2,2.8-4,4.2-5.5,4.2c-0.9,0-1.7-0.9-2.4-2.6C4,9.9,3.4,5,2,5
+ C1.9,5,1.5,5.3,0.8,5.8L0,4.8c0.8-0.7,3.5-3.4,4.7-3.5C5.9,1.2,6.7,2,7,3.8c0.3,2,0.8,6.1,1.8,6.1c0.9,0,2.5-3.4,2.6-4
+ c0.1-0.9-0.3-1.9-2.3-1.1c0.8-2.6,2.3-3.8,4.5-3.8C15.3,1.1,16.1,2.2,16,4.3z"/>
+</svg>
diff --git a/demo/src/sprite/icon-youtube.svg b/demo/src/sprite/icon-youtube.svg
new file mode 100755
index 00000000..8b5d6897
--- /dev/null
+++ b/demo/src/sprite/icon-youtube.svg
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Generator: Adobe Illustrator 19.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
+ width="16px" height="16px" viewBox="0 0 16 16" enable-background="new 0 0 16 16" xml:space="preserve">
+<path d="M15.8,4.8c-0.2-1.3-0.8-2.2-2.2-2.4C11.4,2,8,2,8,2S4.6,2,2.4,2.4C1,2.6,0.3,3.5,0.2,4.8C0,6.1,0,8,0,8
+ s0,1.9,0.2,3.2c0.2,1.3,0.8,2.2,2.2,2.4C4.6,14,8,14,8,14s3.4,0,5.6-0.4c1.4-0.3,2-1.1,2.2-2.4C16,9.9,16,8,16,8S16,6.1,15.8,4.8z
+ M6,11V5l5,3L6,11z"/>
+</svg>