commit b0a2712b2caf4a31613586a9ae5ac538d97cac9d Author: Joshua Seigler Date: Thu Oct 13 16:38:09 2016 -0400 initial commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..64c732f --- /dev/null +++ b/.gitignore @@ -0,0 +1,6 @@ +# 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/ +/presentation-bundle.html diff --git a/README.md b/README.md new file mode 100644 index 0000000..85460a5 --- /dev/null +++ b/README.md @@ -0,0 +1,18 @@ +#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 + +## How to Use: + +Use `npm run start` to serve the project folder on `localhost` and launch it in your default browser. + +After you have edited index.html to your liking, you can run `npm run build` to compile the whole presentation into a single portable file for use elsewhere. + +## Gotchas: + +Firefox and Chrome handle `file:///` urls differently. In Firefox, local files are allowed to interact with LocalStorage, but on Chrome they are not. To circumvent this issue, you have to serve the file on `localhost` with `npm run start` or some other local server. \ No newline at end of file diff --git a/index.html b/index.html new file mode 100644 index 0000000..1e987b3 --- /dev/null +++ b/index.html @@ -0,0 +1,59 @@ + + + + + Janus Presentation Framework + + + + + +
+ +
+
+ +

Block

+
+
+ +

Chain

+
+
+ +
+ + +

Hash Pointers

+
+ +
+

Credits

+
+ Steven Depolo, Flickr + Pixabay +
+
+ +
+ + + + diff --git a/libs/openjs-shortcut/shortcut.js b/libs/openjs-shortcut/shortcut.js new file mode 100644 index 0000000..6a906f4 --- /dev/null +++ b/libs/openjs-shortcut/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/package.json b/package.json new file mode 100644 index 0000000..2a6df3b --- /dev/null +++ b/package.json @@ -0,0 +1,14 @@ +{ + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1", + "build": "inliner index.html > presentation-bundle.html", + "start": "http-server -o -cors" + }, + "author": "Joshua Seigler", + "devDependencies": { + "inliner": "^1.9.5" + }, + "dependencies": { + "http-server": "^0.9.0" + } +} diff --git a/scripts/app.js b/scripts/app.js new file mode 100644 index 0000000..4cbd386 --- /dev/null +++ b/scripts/app.js @@ -0,0 +1,131 @@ +(function () { + 'use strict'; + + var slides = [], + currentSlideNumber = 0, + slideNext, + slidePrev, + commandBar, + commandField, + commandBarVisible = true; + + function $(selector) { + return document.querySelector(selector); + } + function $$(selector) { + return Array.prototype.slice.call(document.querySelectorAll(selector), 0); + } + + function setCurrentSlide(newSlideNumber, storeChange) { + newSlideNumber = Math.max(Math.min(newSlideNumber, slides.length - 1), 0); + if (newSlideNumber !== currentSlideNumber) { + currentSlideNumber = newSlideNumber; + if (storeChange) { + localStorage.setItem('janus-currentSlideNumber', currentSlideNumber); + } + } + slides.forEach(function (item, index, array) { + if (index < currentSlideNumber) { + if (slides[index].contains(slides[currentSlideNumber])) { + item.setAttribute('janus-timeline', 'present'); + } else { + item.setAttribute('janus-timeline', 'past'); + } + } else if (index === currentSlideNumber) { + item.setAttribute('janus-timeline', 'present'); + } else { + item.setAttribute('janus-timeline', 'future'); + } + }); + } + + var sessionListener = function(e) { + if (e.url === window.location.href) { + if (e.key === 'janus-currentSlideNumber') { + setCurrentSlide(+e.newValue, false); + } + } + }; + + var toggleCommandBar = function(visible) { + if (visible === false) { + commandBar.style.display = 'none'; + commandBarVisible = false; + } else if (visible === true) { + commandBar.style.display = 'flex'; + commandField.value = ''; + commandField.focus(); + commandBarVisible = true; + } + } + + var commandListener = function(event) { + var typed = String.fromCharCode(event.keyCode).toLowerCase(); + if (/[0-9]/.test(typed)) { + return; + } else if (event.keyCode === 13) { + runCommand(commandField.value); + toggleCommandBar(false); + } else if (/[spc]/.test(typed)) { + runCommand(commandField.value + typed); + toggleCommandBar(false); + } + }; + + var runCommand = function(command) { + var s = command.split(); + if (s.length === 1 && /^[0-9]+$/.test(s[0])) { + setCurrentSlide(+s[0], true); + } else if (s.length === 1) { + switch(s[0]) { + case 's': + document.body.classList.toggle('simulate-projection'); + break; + case 'p': + document.body.classList.toggle('show-notes'); + break; + case 'c': + window.open(window.location.href, '_blank'); + break; + } + } + } + + var init = function() { + commandField = $('#commandField'); + commandField.addEventListener('keydown', commandListener); + commandField.addEventListener('blur', function(event) { + toggleCommandBar(false); + }); + commandBar = $('body > nav'); + toggleCommandBar(false); + + slides = $$('main>section, [janus-timeline]'); + currentSlideNumber = 0; + shortcut.add('F1', function() { + document.body.classList.toggle('show-notes'); + }); + shortcut.add('F2', function() { + window.open(window.location.href, '_blank'); + }); + shortcut.add('Page_down', function() { + setCurrentSlide(currentSlideNumber + 1, true); + }); + shortcut.add('Page_up', function() { + setCurrentSlide(currentSlideNumber - 1, true); + }); + shortcut.add('Escape', function() { + toggleCommandBar(!commandBarVisible); + }); + var storedSlideNumber; + if (storedSlideNumber = localStorage.getItem('janus-currentSlideNumber')) { + setCurrentSlide(storedSlideNumber, false); + } else { + setCurrentSlide(0); + } + document.body.classList.remove('is-loading'); + }; + + document.addEventListener('DOMContentLoaded', init); + window.addEventListener('storage', sessionListener); +})(); diff --git a/styles/blockchain.css b/styles/blockchain.css new file mode 100644 index 0000000..86fc676 --- /dev/null +++ b/styles/blockchain.css @@ -0,0 +1,42 @@ +.credits > a { + display: block; +} + +img.thumbnail { + height: 1em; +} + +.row, .col { + display: flex; + flex-grow: 1; + flex-basis: 0; +} + +.row { + flex-direction: row; +} + +.col { + flex-direction: column; +} + +.row > div, .col > div { + position: relative; + justify-content: center; +} + +.title-page h1 { + font-size: 2em; + padding: 0.25em; + text-transform: uppercase; +} + +.credits { + padding: 0.5em; + text-align: left; + justify-content: flex-start; +} +.credits > div > a { + display: block; + font-size: 0.75em; +} diff --git a/styles/blocks.jpg b/styles/blocks.jpg new file mode 100644 index 0000000..3a3143e Binary files /dev/null and b/styles/blocks.jpg differ diff --git a/styles/chains.jpg b/styles/chains.jpg new file mode 100644 index 0000000..c5707e6 Binary files /dev/null and b/styles/chains.jpg differ diff --git a/styles/linked-list-hashpointers.svg b/styles/linked-list-hashpointers.svg new file mode 100644 index 0000000..d542232 --- /dev/null +++ b/styles/linked-list-hashpointers.svg @@ -0,0 +1,233 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/styles/linked-list.svg b/styles/linked-list.svg new file mode 100644 index 0000000..3ef9ca6 --- /dev/null +++ b/styles/linked-list.svg @@ -0,0 +1,195 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + diff --git a/styles/main.css b/styles/main.css new file mode 100644 index 0000000..1b54136 --- /dev/null +++ b/styles/main.css @@ -0,0 +1,225 @@ +/* Basics */ + +*, *:before, *:after { + box-sizing: inherit; + margin: 0; + padding: 0; +} + +:root { + box-sizing: border-box; + font-family: sans-serif; + font-size: calc(3vmax + 3vmin); + cursor: default; +} + +a { + color: inherit; + cursor: pointer; +} + +li { + list-style: none; +} + +code { + font-family: Consolas, monaco, monospace; +} + +kbd { + font-family: Consolas, monaco, monospace; + background-color: hsla(0, 0%, 100%, 0.2); + border-radius: 0.5em; + padding: 0.1em 0.4em 0; + margin: -0.1em 0 0; +} + +h1 { + font-size: 1.5rem; +} +h2 { + font-size: 1rem; +} +h1, h2 { + font-weight: bold; +} + +/* Layout */ +body { + display: flex; + flex-direction: column; + padding: 0; + margin: 0; + background-color: black; + color: white; + overflow: hidden; +} + +body.is-loading:after { + content: 'Loading...'; + font-size: 0.5em; + line-height: 100vh; + color: white; + background-image: linear-gradient(45deg, #030, #000, #003); + position: fixed; + top: 0; + right: 0; + bottom: 0; + left: 0; + text-align: center; + z-index: 100; +} + +body.simulate-projection { + filter: brightness(1.5) contrast(0.65); +} + +main { + margin-top: 0; + perspective: 100vmin; + transform-style: preserve-3d; + height: 100vh; +} + +/* Components */ +nav { + flex-wrap: wrap; + display: flex; + position: fixed; + top: 0; + left: 0; + right: 0; + padding: 0.25em 0.25em 4em; + transition: transform ease 0.5s; + font-size: 0.5rem; + z-index: 2; + background-image: linear-gradient(to top, hsla(0, 0%, 0%, 0), hsla(0, 0%, 0%, 0.5)); +} + +nav > label { + flex: 0 0 auto; + padding-right: 1ch; +} + +nav > input { + flex: 1 1 auto; + padding: 0; + font-size: inherit; + border: none; + background: transparent; + color: inherit; + outline: none; +} + +nav > input:invalid { + color: red; +} + +ul.help { + width: 100%; + flex-shrink: 0; + font-size: 0.5em; +} + +ul.help li { + display: inline-block; + background-color: hsla(0, 0%, 100%, 0.2); + border-radius: 0.5em; + padding: 0 0.5em; +} + +section { + position: absolute; + z-index: 1; + display: flex; + flex-direction: column; + justify-content: center; + width: 100%; + height: 100%; + margin: 0; + overflow: hidden; + text-align: center; + background-color: black; + transition: transform ease 0.5s, opacity ease 0.5s, visibility step-end 0.5s; + transform-origin: 50% 50%; +} + +/* +section > * { + transform: rotate(-7deg); +} +*/ + +[janus-timeline='past'] { + transition: transform ease-in 0.5s, opacity ease-in 0.5s, visibility step-end 0.5s; +} + +[janus-timeline='present'] { + transition: transform ease-out 0.5s, opacity ease-out 0.5s, visibility step-start 0.5s; +} + +[janus-timeline='future'] { + visibility: hidden; +} + +body.show-notes section [janus-timeline='future'] { + visibility: visible; + opacity: 0.25; +} + +body.show-notes section[janus-timeline='future'] [janus-timeline='future'] { + opacity: 1; +} + +section[janus-timeline='past'] { + transform: translate3d(0, 0, 0) scale(5); + opacity: 0; + visibility: hidden; + pointer-events: none; + z-index: 2; +} + +section[janus-timeline='present'] { + transform: none; + opacity: 1; +} + +section[janus-timeline='future'] { + transform: translate3d(0, -5vmin, 0) scale(0.8); + opacity: 0; + visibility: hidden; + pointer-events: none; +} + +img.cover, img.contain { + position: absolute; + top: 0; + left: 0; + height: 100%; + width: 100%; + z-index: -1; + transform: none; +} +img.cover { + object-fit: cover; +} +img.contain { + object-fit: contain; +} + +body.show-notes section { + transition: none; +} + +body.show-notes section[janus-timeline='present'] + section[janus-timeline='future'] { + transform: scale(0.25); + transform-origin: bottom right; + top: auto; + left: auto; + bottom: 0.4rem; + right: 0.4rem; + opacity: 0.75; + visibility: visible; + outline: 0.2rem solid white; + z-index: 3; +}