commit a72967b38d14150c6c6ba27bcf05546423f12387 Author: Joshua Seigler Date: Thu Oct 6 20:11:23 2016 -0400 feat: initial commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..d3f11de --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ +# https://git-scm.com/docs/gitignore +# https://help.github.com/articles/ignoring-files +# Example .gitignore files: https://github.com/github/gitignore +/bower_components/ +/node_modules/ \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..f68b336 --- /dev/null +++ b/README.md @@ -0,0 +1,8 @@ +#JANUS + +This is a browser-based presentation framework with two connected views: one for the presenter, and one for the audience. + +## Features: + +* Presenter view and presentation view, connected through Localstorage +* Specializes in live-coding demos diff --git a/index.html b/index.html new file mode 100644 index 0000000..f082fac --- /dev/null +++ b/index.html @@ -0,0 +1,24 @@ + + + + + Janus Presentation Framework + + + +
+
+

Presentation Title

+
+
+

Slide Two

+ +
+
+

Slide Three

+
+
+ + + + diff --git a/scripts/app.js b/scripts/app.js new file mode 100644 index 0000000..752b489 --- /dev/null +++ b/scripts/app.js @@ -0,0 +1,44 @@ +(function () { + 'use strict'; + + var slides = [], + currentSlideNumber = 0, + slideNext, + slidePrev; + + function $$(selector){ + return Array.prototype.slice.call(document.querySelectorAll(selector), 0); + } + + function moveSlides() { + slides.forEach(function (item, index, array) { + if (index < currentSlideNumber) { + item.setAttribute('janus-timeline', 'past'); + } else if (index == currentSlideNumber) { + item.setAttribute('janus-timeline', 'present'); + } else { + item.setAttribute('janus-timeline', 'future'); + } + }); + } + + var init = function() { + slides = $$('main>section'); + currentSlideNumber = 0; + shortcut.add('Page_down', function() { + if (currentSlideNumber < slides.length - 1) { + currentSlideNumber++; + moveSlides(); + } + }); + shortcut.add('Page_up', function() { + if (currentSlideNumber > 0) { + currentSlideNumber--; + moveSlides(); + } + }); + moveSlides(); + } + + document.addEventListener("DOMContentLoaded", init); +})(); diff --git a/scripts/shortcut.js b/scripts/shortcut.js new file mode 100644 index 0000000..6a906f4 --- /dev/null +++ b/scripts/shortcut.js @@ -0,0 +1,223 @@ +/** + * http://www.openjs.com/scripts/events/keyboard_shortcuts/ + * Version : 2.01.B + * By Binny V A + * License : BSD + */ +shortcut = { + 'all_shortcuts':{},//All the shortcuts are stored in this array + 'add': function(shortcut_combination,callback,opt) { + //Provide a set of default options + var default_options = { + 'type':'keydown', + 'propagate':false, + 'disable_in_input':false, + 'target':document, + 'keycode':false + } + if(!opt) opt = default_options; + else { + for(var dfo in default_options) { + if(typeof opt[dfo] == 'undefined') opt[dfo] = default_options[dfo]; + } + } + + var ele = opt.target; + if(typeof opt.target == 'string') ele = document.getElementById(opt.target); + var ths = this; + shortcut_combination = shortcut_combination.toLowerCase(); + + //The function to be called at keypress + var func = function(e) { + e = e || window.event; + + if(opt['disable_in_input']) { //Don't enable shortcut keys in Input, Textarea fields + var element; + if(e.target) element=e.target; + else if(e.srcElement) element=e.srcElement; + if(element.nodeType==3) element=element.parentNode; + + if(element.tagName == 'INPUT' || element.tagName == 'TEXTAREA') return; + } + + //Find Which key is pressed + if (e.keyCode) code = e.keyCode; + else if (e.which) code = e.which; + var character = String.fromCharCode(code).toLowerCase(); + + if(code == 188) character=","; //If the user presses , when the type is onkeydown + if(code == 190) character="."; //If the user presses , when the type is onkeydown + + var keys = shortcut_combination.split("+"); + //Key Pressed - counts the number of valid keypresses - if it is same as the number of keys, the shortcut function is invoked + var kp = 0; + + //Work around for stupid Shift key bug created by using lowercase - as a result the shift+num combination was broken + var shift_nums = { + "`":"~", + "1":"!", + "2":"@", + "3":"#", + "4":"$", + "5":"%", + "6":"^", + "7":"&", + "8":"*", + "9":"(", + "0":")", + "-":"_", + "=":"+", + ";":":", + "'":"\"", + ",":"<", + ".":">", + "/":"?", + "\\":"|" + } + //Special Keys - and their codes + var special_keys = { + 'esc':27, + 'escape':27, + 'tab':9, + 'space':32, + 'return':13, + 'enter':13, + 'backspace':8, + + 'scrolllock':145, + 'scroll_lock':145, + 'scroll':145, + 'capslock':20, + 'caps_lock':20, + 'caps':20, + 'numlock':144, + 'num_lock':144, + 'num':144, + + 'pause':19, + 'break':19, + + 'insert':45, + 'home':36, + 'delete':46, + 'end':35, + + 'pageup':33, + 'page_up':33, + 'pu':33, + + 'pagedown':34, + 'page_down':34, + 'pd':34, + + 'left':37, + 'up':38, + 'right':39, + 'down':40, + + 'f1':112, + 'f2':113, + 'f3':114, + 'f4':115, + 'f5':116, + 'f6':117, + 'f7':118, + 'f8':119, + 'f9':120, + 'f10':121, + 'f11':122, + 'f12':123 + } + + var modifiers = { + shift: { wanted:false, pressed:false}, + ctrl : { wanted:false, pressed:false}, + alt : { wanted:false, pressed:false}, + meta : { wanted:false, pressed:false} //Meta is Mac specific + }; + + if(e.ctrlKey) modifiers.ctrl.pressed = true; + if(e.shiftKey) modifiers.shift.pressed = true; + if(e.altKey) modifiers.alt.pressed = true; + if(e.metaKey) modifiers.meta.pressed = true; + + for(var i=0; k=keys[i],i 1) { //If it is a special key + if(special_keys[k] == code) kp++; + + } else if(opt['keycode']) { + if(opt['keycode'] == code) kp++; + + } else { //The special keys did not match + if(character == k) kp++; + else { + if(shift_nums[character] && e.shiftKey) { //Stupid Shift key bug created by using lowercase + character = shift_nums[character]; + if(character == k) kp++; + } + } + } + } + + if(kp == keys.length && + modifiers.ctrl.pressed == modifiers.ctrl.wanted && + modifiers.shift.pressed == modifiers.shift.wanted && + modifiers.alt.pressed == modifiers.alt.wanted && + modifiers.meta.pressed == modifiers.meta.wanted) { + callback(e); + + if(!opt['propagate']) { //Stop the event + //e.cancelBubble is supported by IE - this will kill the bubbling process. + e.cancelBubble = true; + e.returnValue = false; + + //e.stopPropagation works in Firefox. + if (e.stopPropagation) { + e.stopPropagation(); + e.preventDefault(); + } + return false; + } + } + } + this.all_shortcuts[shortcut_combination] = { + 'callback':func, + 'target':ele, + 'event': opt['type'] + }; + //Attach the function with the event + if(ele.addEventListener) ele.addEventListener(opt['type'], func, false); + else if(ele.attachEvent) ele.attachEvent('on'+opt['type'], func); + else ele['on'+opt['type']] = func; + }, + + //Remove the shortcut - just specify the shortcut and I will remove the binding + 'remove':function(shortcut_combination) { + shortcut_combination = shortcut_combination.toLowerCase(); + var binding = this.all_shortcuts[shortcut_combination]; + delete(this.all_shortcuts[shortcut_combination]) + if(!binding) return; + var type = binding['event']; + var ele = binding['target']; + var callback = binding['callback']; + + if(ele.detachEvent) ele.detachEvent('on'+type, callback); + else if(ele.removeEventListener) ele.removeEventListener(type, callback, false); + else ele['on'+type] = false; + } +} diff --git a/styles/30000-light-stripes.gif b/styles/30000-light-stripes.gif new file mode 100644 index 0000000..ec3b573 Binary files /dev/null and b/styles/30000-light-stripes.gif differ diff --git a/styles/main.css b/styles/main.css new file mode 100644 index 0000000..c520172 --- /dev/null +++ b/styles/main.css @@ -0,0 +1,95 @@ +/* Basics */ + +*, *:before, *:after { + box-sizing: inherit; + margin: 0; + padding: 0; +} + +* + * { + margin-top: 1em; +} + +:root { + box-sizing: border-box; + line-height: 1.5; + font-family: sans-serif; + font-size: calc(2vw + 2em); +} + +/* Layout */ +body { + display: flex; + flex-direction: column; + padding: 0; + margin: 0; + background-color: black; + color: white; + /*background-image: url('30000-light-stripes.gif'); + background-size: cover; + box-shadow: 0 0 10vmin black inset, 0 0 10vmin black inset;*/ +} + +main { + margin-top: 0; + perspective: 100vmin; + transform-style: preserve-3d; + overflow: hidden; + height: 100vh; +} + +/* Components */ +section { + position: absolute; + display: flex; + flex-direction: column; + width: 100%; + height: 100%; + margin: 0; + padding: 1em; + overflow: hidden; + transition: transform ease 1s, opacity ease 1s, visibility step-end 1s; + transform-origin: 50% 50%; + text-align: center; +} + +[janus-timeline='past'] { +} + +[janus-timeline='present'] { + transition: transform ease 1s, opacity ease 1s, visibility step-start 1s; +} + +[janus-timeline='future'] { + visibility: hidden; +} + +section[janus-timeline='past'] { + transform: translate3d(0, 0, 100vmin); + opacity: 0; + visibility: hidden; + pointer-events: none; +} + +section[janus-timeline='present'] { + transform: none; + opacity: 1; +} + +section[janus-timeline='future'] { + transform: translate3d(0, 0, -25vmin); + opacity: 0; + visibility: hidden; + pointer-events: none; +} + +section.image > img { + position: absolute; + margin: 0; + top: 0; + left: 0; + height: 100%; + width: 100%; + object-fit: cover; + z-index: -1; +}