From 056ce5f777969e249b63a4ad5e0cc6e3b9308699 Mon Sep 17 00:00:00 2001 From: Joshua Seigler Date: Sun, 23 Oct 2016 03:07:58 -0400 Subject: [PATCH] feat: backport lots of improvements from another project --- README.md | 2 +- index.html | 153 ++++++++++++----- libs/prefixfree/prefixfree.min.js | 18 ++ scripts/app.js | 266 +++++++++++++++++++++++------- styles/browser-bar.png | Bin 0 -> 4248 bytes styles/main.css | 264 +++++++++++++++++++++++++---- 6 files changed, 570 insertions(+), 133 deletions(-) create mode 100644 libs/prefixfree/prefixfree.min.js create mode 100644 styles/browser-bar.png 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 0000000000000000000000000000000000000000..eb2679f62f7256d3b2d49717dbf97a499e4fbced GIT binary patch literal 4248 zcmV;J5NGd+P)`HPBzmec^W}Tr z`?~to>&)!J*uQ`O*s7|k`b;MC$GY0OYh$t4tVkqs7Ie`JXa+O`nt`G*V4CKUWHQ+~ zFgWmWG#Y&~l}hy+hYlT@WSZt*67j@}Y&HusYr?Xuq8ZhSGy|Fe&46YAFbo5ciU=wy zD$v{4`${Ad`D-+tPTw;wF>XcbR7!KC8PE)91~da9F+hoJHj`zqcwKx&PjAnGNOi3G z+H^V{l1Z&rGoTsJ3}^=I3{cFa*c+{^s+^TgXYKvEt{Kn_Xa+O`Au>R*H)3W?z2Fui z$y&8$Kr^5jaAJUBZ`8C*K(Dzu@uS-`1DXNNKxhnDun^V3*FV3hR0_#t5}9nKI5#l^ zh*m@qtB#?nvMLX(RCe+PJx+>_#lx0kmkURZvH==H@w3R-L&2!RnGb);5wi*9dygKSGlV^bq)YHARPM0{vDeTZqA7#bQv_t9<^&}(aJQ7Sv9BXO>U zfyLR9d#e*i?$Z8x!t%42*u%o8!kDT*<%n5@4?nWT;X{XY09Isp-M(tFPa_*a{-g|m(q^tIw%DeFV3C%I7cGvPGjBL zg7~>^-8$TK(@hvVcC4HFe0vb=K`?Rv{R90h_|m-W8*jXUl`B^wULWV(%14nu#lWl# zN-#i#SungP-M%y6%5T5Mn00TV?&D8@hHUJmGq zZ(!_u3yrB)fqDzpxEwSi`8Ck>296zj2-bP`0Anwd()aDjUD(jI4zEPofp`tj(#Xc` zOzy{;fv>QluM>BUzZ(}+Uo53>l#t@gIn9A>*th{L%`Ld$h8sqy8`Z$|^W!Li(;E&R zJcyx_Lzs5{G_?gmN&U>4g6!Y^{x=XN)iQbVWUO4VQf`<69yx`>Qa<&5x92O%+gUqOo@^e%S|D(;pLN!j$>0?|KWXYrX;E zEjgn31BPnqfZ95|()Ts2uD7sq!k?8hVamAZjxJj$_^#iu9zXr`6I$oAN{>~sQ&(4q z!$%I|+uh$P2Vt@!$|6;;5HA#bpLpU4)YjDIX?lFs<9Olu7xH!c3Ee=RefC*terUW5 zcDo&~x~iW&Jw4d6WefJ~-2=n>P=~dyb>CqZ4!I&b5n6*S-7+ikUz-T~i#~;LsqRd+s@N*KUf{<0OD~Ld?Tg>48Pbp-TC5iCPT6!eUAO0ZPem_r&6c#!FTcE z#h5mIn#8DKy%ZQF|0TvIaNc?6VPIf@1%s@al^mH1zK%W)2j+aAyhe5@(DuAdn>Vo+ z`9a0YpX%yrq0Ff9c8tZSd!igcKtcD_f4z#j`a0Zq-+h3Q^KVRS3@E747R3>1hqEA9 zy)`@b(vPlaG3=5{F2OZdU&Cbhdve{i*J0+&nV@GBI3Sg46Zs>j#Z~J0=bvX=KArH< zwZ?sM>UV7uVGg<9Uk1GW3pVYL&wTCKAnl1YvP>qr{R>!&{=mp_{nNdTO*^p6mvos~ zz^urLM}{Z%NoRcq=-viv;$l}-)UmDi3m{RG555r-h|s5l3X204%!mQh)-c&y8(b&Boe30cjLy5`0>Xdar^DJWBT;zEZB?2@qSr5T%P70&pr2C{P4pM*t2I3rcRwI zH60;iM@EL@;71xmep8|I!XvA={Nb`L-KRDC!F8GfTSZnMWxks?Z^m7B-IZU!qOla* zuD||z&>n6oUcSiMvO&xz4EA3T#v?16F+D*&NsmdvJOiK#RxFB0S35ESeeFYE0cSPR z)eqCMSn$ozPp$z(jRB@rX4Q5^wNCrB^#6l(>$bX z@rzv+qaDZL!-w(YlTTvIm@)P)JoC&mtnJjPQ~C2zLV^Y_fBa&mWRrwoQAp}}L zq^vkd@xn}cMg2i+(^%h&a6t{1`*_g>wQ18PHfKc{AO&BMyc-{W#x*oFu!lcWCcJOo zK1`WH^Yp=sDi)FtI|B~x)o2Yeet!S`_blKR%2GB~SRbvqcrAYI(AF#a*upyXQz>jK z7HYpbX?nqFY<}9IAR%*-D;EAR^!S?(3HSSkCeudnwMrT5^4 z7u**eRWR9QJq`a#opy}&`mY4b)2tn1sq4N1aBALM;CK&!id+z;`Psr33(OTvhGa!f zWt%Pq`VGLK$y(A?0aRpjFFL0->gzW^vLb!+5_5sUA+{(&bGzJ^|H>VA+`+z%zW@IF=i31OM#X&2~Gm zfIAGqq>PY)Z(koC&ddbKiuBpBlRVEb?R~sX59gsEOj8jbeDDElo-tzv@0L2s*s&|3 z;7i-x=!4JaBSl!rj)((4Se)!Swb^};k>O)xuya|NqpY8_<7CH<9ay+FMo=OxzHxZO5ZdlPMoNW+Y2-47WLb)sLJ~a zz^TS27)$O1Od#>;=eZwZ)aUN>Y--|o4|*3~iJ>KTf@Eni%&TN$4X`FH!_fmKS`M#e zyB%o3jS8EZ=r?e*;!j9VUIsJPAk^0oZN$>%WiXCz#6OZd*lq{JVmSyWlPvRnBs~*L zT9$!ii8Q4mDPCDwi6u*x;GK8gVL_NK>RGd9$(xe2!xi%2OPMbPU+L_IcK?YuP{hJ9 zg?^O5t^z{R&&w~r9BbCBVY^P~gKsaic+}qBj{EPw-`+J+_lsQ;_!v zbL(3%zu_u0RyK(PkAo4FyByDiX*a-!AAZP!;>8!s{rXPD4h7$zfBqTqc${SdWLFqe zhkcW=BO_y{ioO=|g%aN9g^3=;NySTs>)}T~xcFG7qpUvSdC{Upc>C?QF?;rG(0fX4 zeSLk{wQCnTIy%_Y3$?lVBWuf!)9*OaLRmiTAnQ}% zSbi?TCF!yWG2GykO}fec z+U>OGnljw2TepIq13`g;rhaJG3ANMv@mnhtw48z&$H{{lum9Rdx*lG7=_OYf<#fF` zIpJ#x!b#DY)TVluBW@@N(|%woG+w5t*qJb4LSCh;em+3Pj*JY~N5=;re6X;pbgqJ5 z6_*Hzsy@naZ@lqFN3|k9RBdr1e#g;IYQ2IP*H1xBgq_P49=&jR^%d%{pUYfFez0;o zB3xem^zFx~&_bNOEM2o<;+9iZF}RI|Wq=%1-TWx}ttoJKdC>DeZJI z(O0!ZJiM=%G#^?@JEH5L6j)TRAI^~oyNcdY`56RzsW7VWCi15oF_ZsvZK+&es`3%G z56<=R7rNJpfvPc8IC$V-jx~wBe*9~U^br=*UrIYpeipWcjzyKn0*(rC20br{p8>I# z1f$CPA>mIsVh(yO$&4R)?xV`>?hKcupKH<;SB%Aj 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;