diff --git a/README.md b/README.md index 85460a5..62fa15e 100644 --- a/README.md +++ b/README.md @@ -15,4 +15,4 @@ After you have edited index.html to your liking, you can run `npm run build` to ## 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 +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 in Chrome, you have to serve the file on `localhost` with `npm run start` or some other local server. diff --git a/index.html b/index.html index 6403007..b055a91 100644 --- a/index.html +++ b/index.html @@ -2,13 +2,14 @@ - Janus Presentation Framework + Tech Talk: Responsive Typography +
-
-

Janus Presentations

-

Hotkey powered, multi-window presentations

-
- Press Escape for commands. Page Up / Page Down to navigate. -
-
Get the code on GitHub
-
- -
-

Hotkeys

-
- Clone Window: F2 -
-
- Navigation: Page Down, Page Up -
-
- Toggle Presenter Mode: F1 -
-
- -
- -

Self-scaling cover images with object-fit

-
-
-

Simple default markup

-
- Any section tag or item with attribute janus-timeline is added to the timeline and revealed in sequence. -
-
- -
-

Animations controlled by CSS

-
- Framework sets custom attribute janus-timeline to past, present, or future -
-
- -
-

Cross-window synchronization with JavaScript localStorage events.

+
+

Janus

+

A live-coding web presentation framework.

+

Page Down to continue

+

Esc for commands

-

The end.

+
+

Blockquotes are pretty cool, right?

+ Thomas Jefferson, probably +
+
+ +
+
+
+ +
+
+ +
+ + +
+ +
+ + +
+ +
+ + +
+
+
+
+ +
+

The End

diff --git a/libs/prefixfree/prefixfree.min.js b/libs/prefixfree/prefixfree.min.js new file mode 100644 index 0000000..4c12fff --- /dev/null +++ b/libs/prefixfree/prefixfree.min.js @@ -0,0 +1,18 @@ +/** + * StyleFix 1.0.3 & PrefixFree 1.0.7 + * @author Lea Verou + * MIT license + */ +(function(){function k(a,b){return[].slice.call((b||document).querySelectorAll(a))}if(window.addEventListener){var e=window.StyleFix={link:function(a){var c=a.href||a.getAttribute("data-href");try{if(!c||"stylesheet"!==a.rel||a.hasAttribute("data-noprefix"))return}catch(b){return}var d=c.replace(/[^\/]+$/,""),h=(/^[a-z]{3,10}:/.exec(d)||[""])[0],l=(/^[a-z]{3,10}:\/\/[^\/]+/.exec(d)||[""])[0],g=/^([^?]*)\??/.exec(c)[1],m=a.parentNode,f=new XMLHttpRequest,n;f.onreadystatechange=function(){4===f.readyState&& +n()};n=function(){var b=f.responseText;if(b&&a.parentNode&&(!f.status||400>f.status||600' + markupEl.value + '' + scriptEl.value + ''; + frameWindow.document.open(); + frameWindow.document.write(compiled); + frameWindow.document.close(); +// frameEl.src = 'data:text/html;charset=utf-8,' + encodeURI(compiled); + } +// listener = function () { +// if (this.timeoutId) { +// window.clearTimeout(this.timeoutId); +// } +// this.timeoutId = window.setTimeout(editorAction, 100); +// }; + [markupEl, styleEl, scriptEl].forEach(function (current, index, array) { + var syncFormElementsIndex = syncFormElements.indexOf(current); + current.addEventListener('keyup', editorAction); + if (syncFormElementsIndex >= 0) { + // add a listener to receive changes from localStorage + localStorageActions['janus-input-' + syncFormElementsIndex] = function (event) { + var storedValue = event.newValue, + decodedValue = storedValue.split('/', 2); + decodedValue.push(storedValue.slice(decodedValue.join(' ').length + 1)); + current.value = decodedValue[2]; + current.setSelectionRange(+decodedValue[0], +decodedValue[1]); + editorAction(); + current.focus(); + }; + } + }); + editorAction(); + } + + function init() { + var storedSlideNumber; commandField = $('#commandField'); commandField.addEventListener('keydown', commandListener); + commandField.addEventListener('blur', function (event) { + toggleCommandBar(false); + }); commandBar = $('body > nav'); - toggleCommandBar(); + 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() { + shortcut.add('Page_down', function () { setCurrentSlide(currentSlideNumber + 1, true); }); - shortcut.add('Page_up', function() { + shortcut.add('Page_up', function () { setCurrentSlide(currentSlideNumber - 1, true); }); - shortcut.add('Escape', toggleCommandBar); - var storedSlideNumber; - if (storedSlideNumber = localStorage.getItem('janus-currentSlideNumber')) { + shortcut.add('Escape', function () { + toggleCommandBar(!commandBarVisible); + }); + + storedSlideNumber = localStorage.getItem('janus-currentSlideNumber'); + if (storedSlideNumber) { setCurrentSlide(storedSlideNumber, false); } else { setCurrentSlide(0); } + + document.addEventListener('mousemove', mouseListener); + + localStorageActions = { + 'janus-currentSlideNumber': function (event) { + setCurrentSlide(+event.newValue, false); + }, + 'mouse-x' : function (event) { + setMouseX(event.newValue, false); + } + }; + + $$('[janus-sync]').forEach(function (current, index, array) { + var currentKey, storedValue, decodedValue, group; + syncFormElements.push(current); + if (current.type === 'textarea' || current.type === 'text') { + currentKey = 'janus-input-' + index; + storedValue = localStorage.getItem(currentKey); + if (storedValue) { + decodedValue = storedValue.split('/', 2); + decodedValue.push(storedValue.slice(decodedValue.join(' ').length + 1)); + current.value = decodedValue[2]; + current.setSelectionRange(+decodedValue[0], +decodedValue[1]); + } else { + localStorage.setItem(currentKey, '0/0/' + current.value); + } + // add a listener to store changes + current.addEventListener('keyup', function () { + localStorage.setItem(currentKey, current.selectionStart + '/' + current.selectionEnd + '/' + current.value); + }); + // add a listener to respond to localStorage updates + if (!localStorageActions[currentKey]) { + localStorageActions[currentKey] = function (event) { + var storedValue = event.newValue, + decodedValue = storedValue.split('/', 2); + decodedValue.push(storedValue.slice(decodedValue.join(' ').length + 1)); + current.value = decodedValue[2]; + current.focus(); + current.setSelectionRange(+decodedValue[0], +decodedValue[1]); + }; + } + } else if (current.type === 'checkbox') { + currentKey = 'janus-input-' + index; + storedValue = localStorage.getItem(currentKey); + if (storedValue !== null) { + current.checked = (storedValue === 'true'); + } else { + localStorage.setItem(currentKey, current.checked); + } + // add a listener to store changes + current.addEventListener('change', function () { + localStorage.setItem(currentKey, current.checked); + }); + // add a listener to respond to localStorage updates + if (!localStorageActions[currentKey]) { + localStorageActions[currentKey] = function (event) { + current.checked = (event.newValue === 'true'); + }; + } + } else if (current.type === 'radio') { + group = current.getAttribute('name'); + currentKey = 'janus-input-' + group; + storedValue = localStorage.getItem(currentKey); + if (storedValue !== null && +storedValue === index) { + current.checked = true; + } else if (current.checked) { + localStorage.setItem(currentKey, index); + } + // add a listener to store changes + current.addEventListener('change', function () { + localStorage.setItem(currentKey, index); + }); + // add a listener to respond to localStorage updates + if (!localStorageActions[currentKey]) { + localStorageActions[currentKey] = function (event) { + syncFormElements[+event.newValue].checked = true; + }; + } + } + }); + + $$('.live-coding').forEach(function (current, index, array) { + editorListenerGenerator(current); + }); + document.body.classList.remove('is-loading'); - }; + } document.addEventListener('DOMContentLoaded', init); window.addEventListener('storage', sessionListener); -})(); +}()); diff --git a/styles/browser-bar.png b/styles/browser-bar.png new file mode 100644 index 0000000..eb2679f Binary files /dev/null and b/styles/browser-bar.png differ diff --git a/styles/main.css b/styles/main.css index d9dfa91..cac68e3 100644 --- a/styles/main.css +++ b/styles/main.css @@ -7,15 +7,33 @@ } :root { + --main-font: sans-serif; + --monospace-font: monospace; + --mouse-x: 100vw; + box-sizing: border-box; - font-family: sans-serif; - font-size: calc(2vw + 2em); + font-family: var(--main-font); + font-size: calc(5vw); cursor: default; + line-height: 1.1; + box-sizing: border-box; +} + +::selection { + text-shadow: none; + background: #FF0; + color: black; } a { color: inherit; cursor: pointer; + text-decoration: none; + display: inline-block; + background-image: linear-gradient(to right, currentcolor, currentcolor); + background-position: 0 1.9ex; + background-repeat: repeat-x; + background-size: 8px 0.08ex; } li { @@ -23,29 +41,83 @@ li { } code { - font-family: Consolas, monaco, monospace; + font-family: monospace; + font-family: var(--monospace-font, 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; + font-size: 0.7em; + border-radius: 0.2em; + padding: 0.1em; + font-family: inherit; + text-transform: uppercase; + display: inline-block; + border: 0.1em solid; +} + +textarea { + font-family: monospace; + font-family: var(--monospace-font, monospace); + font-size: 0.5em; + height: 100%; } h1 { - font-size: 1.5rem; - position: relative; - margin: 0 -10vw; - padding: 0 10vw 0.1em; - background-color: hsla(0, 0%, 100%, 0.2); + font-size: 1.5em; + font-weight: 400; } h2 { - font-size: 1rem; + font-size: 1em; + font-weight: 900; } -h1, h2 { - font-weight: bold; + +sup { + display: inline-block; + margin-top: -0.5em; +} + +sub { + display: inline-block; + margin-bottom: -0.5em; +} + +img.thumbnail { + height: 1em; +} + +iframe { + background-color: white; +} + +blockquote { + quotes: "\201C""\201D""\2018""\2019"; + text-align: left; + margin: 0 2em; +} + +blockquote > p::before, blockquote > p::after { + display: inline-block; + position: absolute; + margin: -0.2em; + font-size: 4em; + opacity: 0.25; + pointer-events: none; +} +blockquote > p::before { + content: open-quote; +} +blockquote > p::after { + content: close-quote; +} + +blockquote > cite { + font-style: normal; + font-size: 0.8em; + text-align: right; +} + +blockquote > cite::before { + content: '- '; } /* Layout */ @@ -56,6 +128,11 @@ body { margin: 0; background-color: black; color: white; + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; overflow: hidden; } @@ -75,7 +152,7 @@ body.is-loading:after { } body.simulate-projection { - filter: brightness(1.5) contrast(0.65); + filter: contrast(0.8); } main { @@ -85,6 +162,27 @@ main { height: 100vh; } +.row, .col { + display: flex; + flex-grow: 1; + flex-basis: 0; + align-items: stretch; +} + +.row--shrink, .col--shrink { + flex: 0 1 auto; + align-self: center; +} + +.row { + flex-direction: row; +} + +.col { + flex-direction: column; + align-items: stretch; +} + /* Components */ nav { flex-wrap: wrap; @@ -93,11 +191,11 @@ nav { top: 0; left: 0; right: 0; - padding: 0.25em 0.25em 4em; + padding: 0.25em 0.25em 6em; 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)); + background-image: linear-gradient(to top, hsla(0, 0%, 0%, 0), hsla(0, 0%, 0%, 1)); } nav > label { @@ -127,7 +225,7 @@ ul.help { ul.help li { display: inline-block; - background-color: hsla(0, 0%, 100%, 0.2); + background-color: hsla(0, 0%, 40%, 0.6); border-radius: 0.5em; padding: 0 0.5em; } @@ -141,7 +239,6 @@ section { width: 100%; height: 100%; margin: 0; - padding: 1em; overflow: hidden; text-align: center; background-color: black; @@ -149,34 +246,134 @@ section { transform-origin: 50% 50%; } -/* -section > * { - transform: rotate(-7deg); +/* live-coding */ + +.live-coding { + display: flex; + flex: 1 1 100%; } -*/ + +.live-coding textarea { + font-size: 0.5em; + resize: none; + flex: 1 1 auto; + color: white; + background: #333; + border: none; + padding: 0.1em; + outline: none; +} + +.live-coding textarea::selection { + background-color: black; + color: var(--theme-color, white); +} + +.live-coding__component { + display: flex; + flex: 1 1 auto; +} + +.col > .live-coding__component { + flex-direction: column; +} + +.live-coding__component label { + line-height: 1; + color: var(--theme-color, inherit); +} + +.hidden, +.live-coding input[type="radio"], +.live-coding input[type="checkbox"], +.live-coding input[type="radio"]:not(:checked) + .live-coding__component > textarea, +.live-coding input[type="checkbox"]:not(:checked) + .live-coding__component > textarea { + position: fixed; + visibility: hidden; + right: 110vw; +} + +.live-coding input[type="radio"]:not(:checked) + .live-coding__component, +.live-coding input[type="checkbox"]:not(:checked) + .live-coding__component { + flex: 0 1 auto; +} + +.row > .live-coding__component label { + writing-mode: vertical-rl; + text-align: right; + transform: rotate(180deg); + border-left: 0.1em solid var(--theme-color, currentcolor); + line-height: 1; + flex: 0 0 auto; +} + +.col > .live-coding__component label { + text-align: left; + max-height: 1em; + border-bottom: 0.1em solid var(--theme-color, currentcolor); +} + +/* adapted from Lea Verou's http://dabblet.com/gist/14cf7ecbd12505768478b36510f623c8 */ +.browser { + position: relative; + width: 100%; + height: 100%; + max-width: 100%; + max-height: 100%; + overflow: auto; + margin: 0 auto; + border-radius: 0.5vmin; + overflow: hidden; + --chrome-height: 4vmin; + padding-top: var(--chrome-height); + background-color: #DDD; +} + +.browser::before { + content: ""; + position: absolute; + top: 0; right: 0; left: 0; + border: solid; + --right: 146; --left: 201; + border-width: var(--chrome-height) calc(var(--right) / 38 * var(--chrome-height)) 0 calc(var(--left) / 38 * var(--chrome-height)); + border-image: url('browser-bar.png') 100% var(--right) 0 var(--left) repeat; +} + +.browser iframe { + pointer-events: none; + flex: 1 1 auto; + height: 100%; + width: 100%; +} + +/* states and transitions */ [janus-timeline='past'] { - transition: transform ease-in 0.5s, opacity ease-in 0.5s, visibility step-end 0.5s; + transition: transform ease 0.5s, opacity ease 0.5s, visibility step-end 0.5s; } +section[janus-timeline='present'] [janus-timeline='past'] { + transition: transform ease 0.5s, opacity ease 0.5s; +} [janus-timeline='present'] { - transition: transform ease-out 0.5s, opacity ease-out 0.5s, visibility step-start 0.5s; + transition: transform ease 0.5s, opacity ease 0.5s, visibility step-start 0.5s; } [janus-timeline='future'] { + opacity: 0; visibility: hidden; } body.show-notes section [janus-timeline='future'] { visibility: visible; - opacity: 0.25; + opacity: 0.4; } body.show-notes section[janus-timeline='future'] [janus-timeline='future'] { opacity: 1; } -section[janus-timeline='past'] { +section[janus-timeline='past'], body:not(.show-notes) [janus-timeline='past'][janus-past='big'], body:not(.show-notes) [janus-timeline='future'][janus-future='big'] { transform: translate3d(0, 0, 0) scale(5); opacity: 0; visibility: hidden; @@ -196,16 +393,21 @@ section[janus-timeline='future'] { pointer-events: none; } -img.cover { +img.cover, img.contain { position: absolute; top: 0; left: 0; height: 100%; width: 100%; - object-fit: cover; z-index: -1; transform: none; } +img.cover { + object-fit: cover; +} +img.contain { + object-fit: contain; +} body.show-notes section { transition: none;