Run prettier

This commit is contained in:
ian ramzy 2020-03-30 14:16:08 -04:00
parent d131909b8e
commit f9b94795e7
18 changed files with 4468 additions and 3669 deletions

View File

@ -1,20 +1,32 @@
<!DOCTYPE html> <!DOCTYPE html>
<html> <html>
<head> <head>
<meta charset="UTF-8"/> <meta charset="UTF-8" />
<title>Neon Chat</title> <title>Neon Chat</title>
<link rel="shortcut icon" href="/images/logo.svg"> <link rel="shortcut icon" href="/images/logo.svg" />
<link rel="stylesheet" href="../css/chat.css"> <link rel="stylesheet" href="../css/chat.css" />
<link rel="stylesheet" href="../css/snackbar.css"> <link rel="stylesheet" href="../css/snackbar.css" />
<script src="https://kit.fontawesome.com/9d7bb7e31a.js" crossorigin="anonymous"></script> <script
src="https://kit.fontawesome.com/9d7bb7e31a.js"
crossorigin="anonymous"
></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.0.0/jquery.min.js"></script> <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.0.0/jquery.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jqueryui/1.11.4/jquery-ui.min.js"></script> <script src="https://ajax.googleapis.com/ajax/libs/jqueryui/1.11.4/jquery-ui.min.js"></script>
<meta property="og:title" content="Join your friends call - Neonchat"> <meta property="og:title" content="Join your friends call - Neonchat" />
<meta property="og:description" content="Click the link to join this chat room using Neonchat"> <meta
<meta property="og:image" content="https://neonchat.io/images/preview.png"> property="og:description"
<meta property="og:url" content="https://neonchat.io/"> content="Click the link to join this chat room using Neonchat"
/>
<meta
property="og:image"
content="https://neonchat.io/images/preview.png"
/>
<meta property="og:url" content="https://neonchat.io/" />
<!-- Global site tag (gtag.js) - Google Analytics --> <!-- Global site tag (gtag.js) - Google Analytics -->
<script async src="https://www.googletagmanager.com/gtag/js?id=UA-162048272-1"></script> <script
async
src="https://www.googletagmanager.com/gtag/js?id=UA-162048272-1"
></script>
<script> <script>
window.dataLayer = window.dataLayer || []; window.dataLayer = window.dataLayer || [];
@ -22,54 +34,47 @@
dataLayer.push(arguments); dataLayer.push(arguments);
} }
gtag('js', new Date()); gtag("js", new Date());
gtag('config', 'UA-162048272-1'); gtag("config", "UA-162048272-1");
</script> </script>
</head> </head>
<body> <body>
<div id="header">
<div id="header">
<a href="/"> <a href="/">
<img src="/images/logo.svg" alt="Neon" width="48" height="48"> <img src="/images/logo.svg" alt="Neon" width="48" height="48" />
<p>Neon Chat</p> <p>Neon Chat</p>
</a> </a>
</div> </div>
<p id="remote-video-text"></p>
<p id="remote-video-text"></p> <video id="remote-video" autoplay ondblclick="{openFullscreen()}"></video>
<video id="remote-video" autoplay ondblclick={openFullscreen()}></video> <div id="moveable">
<div id="moveable">
<p id="local-video-text">No webcam input</p> <p id="local-video-text">No webcam input</p>
<video id="local-video" autoplay muted></video> <video id="local-video" autoplay muted></video>
</div> </div>
<div id="entire-chat">
<div id="entire-chat">
<form class="compose"> <form class="compose">
<textarea type="text" placeholder="Type a message"></textarea> <textarea type="text" placeholder="Type a message"></textarea>
</form> </form>
<div id="chat-zone"> <div id="chat-zone">
<div class="chat-messages"> <div class="chat-messages">
<!-- <div class="message-item customer">-->
<!-- <div class="message-bloc">-->
<!-- <div class="message">Have you tried this chat?</div>-->
<!-- </div>-->
<!-- </div>-->
<!-- <div class="message-item customer">--> <!-- <div class="message-item moderator">-->
<!-- <div class="message-bloc">--> <!-- <div class="message-bloc">-->
<!-- <div class="message">Have you tried this chat?</div>--> <!-- <div class="message">Not yet! It looks awesome</div>-->
<!-- </div>--> <!-- </div>-->
<!-- </div>--> <!-- </div>-->
</div>
<!-- <div class="message-item moderator">-->
<!-- <div class="message-bloc">-->
<!-- <div class="message">Not yet! It looks awesome</div>-->
<!-- </div>-->
<!-- </div>-->
</div> </div>
</div> </div>
</div>
<div class="multi-button">
<div class="multi-button">
<div class="buttonContainer"> <div class="buttonContainer">
<button class="hoverButton" onclick="{muteMicrophone()}"> <button class="hoverButton" onclick="{muteMicrophone()}">
<i id="mic-icon" class="fas fa-microphone fa-xs"></i> <i id="mic-icon" class="fas fa-microphone fa-xs"></i>
@ -95,7 +100,10 @@
<div class="HoverState" id="swap-text">Share Screen</div> <div class="HoverState" id="swap-text">Share Screen</div>
</div> </div>
<div class="buttonContainer"> <div class="buttonContainer">
<button class="hoverButton" onclick="{window.location.href = '/newroom'}"> <button
class="hoverButton"
onclick="{window.location.href = '/newroom'}"
>
<i class="fas fa-phone-slash fa-xs"></i> <i class="fas fa-phone-slash fa-xs"></i>
</button> </button>
<div class="HoverState">End Call</div> <div class="HoverState">End Call</div>
@ -113,16 +121,19 @@
<div class="HoverState" id="chat-text">Show Chat</div> <div class="HoverState" id="chat-text">Show Chat</div>
</div> </div>
<div class="buttonContainer"> <div class="buttonContainer">
<button class="hoverButton" id="pip-button" onclick="{togglePictureInPicture()}"> <button
class="hoverButton"
id="pip-button"
onclick="{togglePictureInPicture()}"
>
<i class="fas fa-external-link-alt fa-xs"></i> <i class="fas fa-external-link-alt fa-xs"></i>
</button> </button>
<div class="HoverState" id="pip-text">Enter Picture in Picture</div> <div class="HoverState" id="pip-text">Enter Picture in Picture</div>
</div> </div>
</div> </div>
<script src="/socket.io/socket.io.js"></script>
<script src="/socket.io/socket.io.js"></script> <script src="../js/snackbar.js"></script>
<script src="../js/snackbar.js"></script> <script src="../js/chat.js"></script>
<script src="../js/chat.js"></script> </body>
</body>
</html> </html>

View File

@ -1,6 +1,5 @@
@import url("https://fonts.googleapis.com/css?family=Fira+Sans:600|Heebo:400,500,700&display=swap"); @import url("https://fonts.googleapis.com/css?family=Fira+Sans:600|Heebo:400,500,700&display=swap");
/*Fade in page on load*/ /*Fade in page on load*/
@-webkit-keyframes fadeIn { @-webkit-keyframes fadeIn {
from { from {
@ -31,9 +30,8 @@
/*Fade in page on load*/ /*Fade in page on load*/
body { body {
background: #16171B; background: #16171b;
margin: 0; margin: 0;
padding: 0; padding: 0;
opacity: 0; /* make things invisible upon start */ opacity: 0; /* make things invisible upon start */
@ -48,7 +46,6 @@ body {
animation-duration: 0.3s; animation-duration: 0.3s;
} }
video { video {
background: #16171a; background: #16171a;
} }
@ -68,26 +65,25 @@ video {
float: left; float: left;
} }
#header p, img { #header p,
img {
float: left; float: left;
padding: 7px; padding: 7px;
} }
#header, a { #header,
a {
color: white; color: white;
text-decoration: none; text-decoration: none;
} }
#moveable { #moveable {
z-index: 100; z-index: 100;
position: absolute; position: absolute;
width: 15%; width: 15%;
cursor: move; cursor: move;
} }
#moveable p { #moveable p {
z-index: 101; z-index: 101;
position: absolute; position: absolute;
@ -130,7 +126,7 @@ video {
/*white-space: nowrap;*/ /*white-space: nowrap;*/
font-weight: bold; font-weight: bold;
text-align: left; text-align: left;
background: rgba(0, 0, 0, 0.20); background: rgba(0, 0, 0, 0.2);
border-radius: 10px; border-radius: 10px;
padding: 10px; padding: 10px;
} }
@ -155,15 +151,13 @@ video {
background-repeat: no-repeat; background-repeat: no-repeat;
background-position: center center; background-position: center center;
box-shadow: 9px 9px 16px #0a0b0c, -9px -9px 16px #222328; box-shadow: 9px 9px 16px #0a0b0c, -9px -9px 16px #222328;
} }
/*Neomorphic buttons*/ /*Neomorphic buttons*/
button { button {
border: none; border: none;
font-size: 1.5rem; font-size: 1.5rem;
transition: all .3s ease-in-out; transition: all 0.3s ease-in-out;
color: gray; color: gray;
background: transparent; background: transparent;
cursor: pointer; cursor: pointer;
@ -187,7 +181,6 @@ button:hover {
-ms-transform: translate(0%, -50%); -ms-transform: translate(0%, -50%);
transform: translate(0%, -50%); transform: translate(0%, -50%);
z-index: 999; z-index: 999;
border-radius: 10px; border-radius: 10px;
background: #16171a; background: #16171a;
@ -218,7 +211,6 @@ button:hover {
/*Neomorphic buttons*/ /*Neomorphic buttons*/
/*simple chat*/ /*simple chat*/
#entire-chat { #entire-chat {
@ -245,14 +237,12 @@ button:hover {
margin: 20px; margin: 20px;
box-sizing: border-box; box-sizing: border-box;
padding: 16px; padding: 16px;
} }
.compose textarea::placeholder { .compose textarea::placeholder {
color: white; color: white;
} }
.compose textarea { .compose textarea {
font-family: inherit; font-family: inherit;
font-size: inherit; font-size: inherit;
@ -266,11 +256,8 @@ button:hover {
/*background: #3a4150;*/ /*background: #3a4150;*/
background-color: rgb(22, 23, 26); background-color: rgb(22, 23, 26);
/*box-shadow: 6px 6px 12px #111314, -6px -6px 12px #292a30;*/ /*box-shadow: 6px 6px 12px #111314, -6px -6px 12px #292a30;*/
} }
#chat-zone { #chat-zone {
padding-top: 20px; padding-top: 20px;
box-sizing: border-box; box-sizing: border-box;
@ -301,12 +288,10 @@ button:hover {
margin-bottom: 20px; margin-bottom: 20px;
} }
#chat-zone .chat-messages .message-item.customer { #chat-zone .chat-messages .message-item.customer {
padding-left: 40px; padding-left: 40px;
} }
/*Your messages*/ /*Your messages*/
#chat-zone .message-item.moderator .message-bloc { #chat-zone .message-item.moderator .message-bloc {
background-color: rgb(22, 23, 26); background-color: rgb(22, 23, 26);
@ -319,17 +304,14 @@ button:hover {
max-width: 100%; max-width: 100%;
border-radius: 20px 20px 20px 5px; border-radius: 20px 20px 20px 5px;
box-shadow: 6px 6px 12px #030506, -6px -6px 12px #23242a; box-shadow: 6px 6px 12px #030506, -6px -6px 12px #23242a;
} }
/*Recieved messages*/ /*Recieved messages*/
#chat-zone .message-item.customer .message-bloc { #chat-zone .message-item.customer .message-bloc {
background-color: rgb(42, 43, 47); background-color: rgb(42, 43, 47);
color: #fff; color: #fff;
border-radius: 20px 20px 5px 20px; border-radius: 20px 20px 5px 20px;
box-shadow: 6px 6px 12px #030506, -6px -6px 12px #22232a; box-shadow: 6px 6px 12px #030506, -6px -6px 12px #22232a;
} }
#chat-zone .chat-messages .message-item.customer .message-bloc { #chat-zone .chat-messages .message-item.customer .message-bloc {

File diff suppressed because it is too large Load Diff

View File

@ -1,6 +1,6 @@
.snackbar-container { .snackbar-container {
box-shadow: 9px 9px 16px #0a0b0c, -9px -9px 16px #222328; box-shadow: 9px 9px 16px #0a0b0c, -9px -9px 16px #222328;
transition: all .5s ease; transition: all 0.5s ease;
transition-property: top, right, bottom, left, opacity; transition-property: top, right, bottom, left, opacity;
font-family: "Heebo", sans-serif; font-family: "Heebo", sans-serif;
font-size: 14px; font-size: 14px;
@ -15,7 +15,7 @@
bottom: -100px; bottom: -100px;
top: -100px; top: -100px;
opacity: 0; opacity: 0;
z-index: 9999 z-index: 9999;
} }
.snackbar-container .action { .snackbar-container .action {
@ -28,7 +28,7 @@
margin: 0 0 0 24px; margin: 0 0 0 24px;
padding: 0; padding: 0;
min-width: min-content; min-width: min-content;
cursor: pointer cursor: pointer;
} }
@media (min-width: 640px) { @media (min-width: 640px) {
@ -37,7 +37,7 @@
max-width: 568px; max-width: 568px;
display: inline-flex; display: inline-flex;
border-radius: 5px; border-radius: 5px;
margin: 24px margin: 24px;
} }
} }
@ -45,7 +45,7 @@
.snackbar-container { .snackbar-container {
left: 0; left: 0;
right: 0; right: 0;
width: 100% width: 100%;
} }
} }
@ -53,43 +53,44 @@
top: auto !important; top: auto !important;
bottom: 0; bottom: 0;
left: 50%; left: 50%;
transform: translate(-50%, 0) transform: translate(-50%, 0);
} }
.snackbar-pos.bottom-left { .snackbar-pos.bottom-left {
top: auto !important; top: auto !important;
bottom: 0; bottom: 0;
left: 0 left: 0;
} }
.snackbar-pos.bottom-right { .snackbar-pos.bottom-right {
top: auto !important; top: auto !important;
bottom: 0; bottom: 0;
right: 0 right: 0;
} }
.snackbar-pos.top-left { .snackbar-pos.top-left {
bottom: auto !important; bottom: auto !important;
top: 0; top: 0;
left: 0 left: 0;
} }
.snackbar-pos.top-center { .snackbar-pos.top-center {
bottom: auto !important; bottom: auto !important;
top: 0; top: 0;
left: 50%; left: 50%;
transform: translate(-50%, 0) transform: translate(-50%, 0);
} }
.snackbar-pos.top-right { .snackbar-pos.top-right {
bottom: auto !important; bottom: auto !important;
top: 0; top: 0;
right: 0 right: 0;
} }
@media (max-width: 640px) { @media (max-width: 640px) {
.snackbar-pos.bottom-center, .snackbar-pos.top-center { .snackbar-pos.bottom-center,
.snackbar-pos.top-center {
left: 0; left: 0;
transform: none transform: none;
} }
} }

View File

@ -1,26 +1,28 @@
; (function () { (function () {
'use strict' "use strict";
const accordionEl = document.getElementsByClassName('accordion-header') const accordionEl = document.getElementsByClassName("accordion-header");
function openAccordion (parent, panel) { function openAccordion(parent, panel) {
parent.classList.add('is-active') parent.classList.add("is-active");
panel.style.maxHeight = panel.scrollHeight + 'px' panel.style.maxHeight = panel.scrollHeight + "px";
} }
function closeAccordion (parent, panel) { function closeAccordion(parent, panel) {
parent.classList.remove('is-active') parent.classList.remove("is-active");
panel.style.maxHeight = null panel.style.maxHeight = null;
} }
if (accordionEl.length > 0) { if (accordionEl.length > 0) {
for (let i = 0; i < accordionEl.length; i++) { for (let i = 0; i < accordionEl.length; i++) {
const el = accordionEl[i] const el = accordionEl[i];
const parent = el.parentNode const parent = el.parentNode;
const panel = el.nextElementSibling const panel = el.nextElementSibling;
parent.classList.contains('is-active') && openAccordion(parent, panel) parent.classList.contains("is-active") && openAccordion(parent, panel);
el.addEventListener('click', function () { el.addEventListener("click", function () {
parent.classList.contains('is-active') ? closeAccordion(parent, panel) : openAccordion(parent, panel) parent.classList.contains("is-active")
}) ? closeAccordion(parent, panel)
: openAccordion(parent, panel);
});
} }
} }
}()) })();

View File

@ -1,5 +1,5 @@
; (function () { (function () {
'use strict' "use strict";
// Swipe detector // Swipe detector
// https://gist.github.com/chrishaensel/e17c9f3838f246d75fe3bd19d6bb92e8#file-swipe-js // https://gist.github.com/chrishaensel/e17c9f3838f246d75fe3bd19d6bb92e8#file-swipe-js
@ -8,164 +8,188 @@
touchEndX: 0, touchEndX: 0,
minSwipePixels: 30, minSwipePixels: 30,
detectionZone: undefined, detectionZone: undefined,
swipeCallback: function () { }, swipeCallback: function () {},
init: function (detectionZone, callback) { init: function (detectionZone, callback) {
swipe.swipeCallback = callback swipe.swipeCallback = callback;
detectionZone.addEventListener('touchstart', function (event) { detectionZone.addEventListener(
swipe.touchStartX = event.changedTouches[0].screenX "touchstart",
}, false) function (event) {
detectionZone.addEventListener('touchend', function (event) { swipe.touchStartX = event.changedTouches[0].screenX;
swipe.touchEndX = event.changedTouches[0].screenX },
swipe.handleSwipeGesture() false
}, false) );
detectionZone.addEventListener(
"touchend",
function (event) {
swipe.touchEndX = event.changedTouches[0].screenX;
swipe.handleSwipeGesture();
},
false
);
}, },
handleSwipeGesture: function () { handleSwipeGesture: function () {
let direction, moved let direction, moved;
if (swipe.touchEndX <= swipe.touchStartX) { if (swipe.touchEndX <= swipe.touchStartX) {
moved = swipe.touchStartX - swipe.touchEndX moved = swipe.touchStartX - swipe.touchEndX;
direction = 'left' direction = "left";
} }
if (swipe.touchEndX >= swipe.touchStartX) { if (swipe.touchEndX >= swipe.touchStartX) {
moved = swipe.touchEndX - swipe.touchStartX moved = swipe.touchEndX - swipe.touchStartX;
direction = 'right' direction = "right";
} }
if (moved > swipe.minSwipePixels && direction !== 'undefined') { if (moved > swipe.minSwipePixels && direction !== "undefined") {
swipe.swipe(direction, moved) swipe.swipe(direction, moved);
} }
}, },
swipe: function (direction, movedPixels) { swipe: function (direction, movedPixels) {
let ret = {} let ret = {};
ret.direction = direction ret.direction = direction;
ret.movedPixels = movedPixels ret.movedPixels = movedPixels;
swipe.swipeCallback(ret) swipe.swipeCallback(ret);
} },
} };
const carousels = document.getElementsByClassName('carousel-items') const carousels = document.getElementsByClassName("carousel-items");
// Rotate the carousel forward or backward // Rotate the carousel forward or backward
function rotateCarousel(el, dir) { function rotateCarousel(el, dir) {
if (dir === undefined) { if (dir === undefined) {
dir = 'next' dir = "next";
} }
let currentItem = el.getElementsByClassName('carousel-item is-active')[0] let currentItem = el.getElementsByClassName("carousel-item is-active")[0];
let nextItem = (dir === 'next') ? currentItem.nextElementSibling : currentItem.previousElementSibling let nextItem =
let index = currentItem.getAttribute('data-carousel') dir === "next"
let currentBullet = el.parentNode.getElementsByClassName('carousel-bullet')[index] ? currentItem.nextElementSibling
let nextBullet = (dir === 'next') ? currentBullet.nextElementSibling : currentBullet.previousElementSibling : currentItem.previousElementSibling;
currentItem.classList.remove('is-active') let index = currentItem.getAttribute("data-carousel");
currentBullet.classList.remove('is-active') let currentBullet = el.parentNode.getElementsByClassName("carousel-bullet")[
index
];
let nextBullet =
dir === "next"
? currentBullet.nextElementSibling
: currentBullet.previousElementSibling;
currentItem.classList.remove("is-active");
currentBullet.classList.remove("is-active");
if (nextItem) { if (nextItem) {
nextItem.classList.add('is-active') nextItem.classList.add("is-active");
nextBullet.classList.add('is-active') nextBullet.classList.add("is-active");
} else { } else {
if (dir === 'next') { if (dir === "next") {
el.firstElementChild.classList.add('is-active') el.firstElementChild.classList.add("is-active");
el.parentNode.getElementsByClassName('carousel-bullets')[0].firstElementChild.classList.add('is-active') el.parentNode
.getElementsByClassName("carousel-bullets")[0]
.firstElementChild.classList.add("is-active");
} else { } else {
el.lastElementChild.classList.add('is-active') el.lastElementChild.classList.add("is-active");
el.parentNode.getElementsByClassName('carousel-bullets')[0].lastElementChild.classList.add('is-active') el.parentNode
.getElementsByClassName("carousel-bullets")[0]
.lastElementChild.classList.add("is-active");
} }
} }
} }
// Equal heights fix // Equal heights fix
function equalHeightCarousel(carousel, items) { function equalHeightCarousel(carousel, items) {
let taller = 0 let taller = 0;
let height let height;
for (let i = 0; i < items.length; i++) { for (let i = 0; i < items.length; i++) {
items[0].parentNode.style.minHeight = taller + 'px' items[0].parentNode.style.minHeight = taller + "px";
items[i].classList.add('is-loading') items[i].classList.add("is-loading");
height = items[i].offsetHeight height = items[i].offsetHeight;
items[i].classList.remove('is-loading') items[i].classList.remove("is-loading");
if (height > taller) { if (height > taller) {
taller = height taller = height;
} }
} }
items[0].parentNode.style.minHeight = taller + 'px' items[0].parentNode.style.minHeight = taller + "px";
} }
// Clear autorotate // Clear autorotate
function clearAutorotate(autorotate) { function clearAutorotate(autorotate) {
if (autorotate) { if (autorotate) {
clearInterval(autorotate) clearInterval(autorotate);
} }
} }
if (carousels.length > 0) { if (carousels.length > 0) {
for (let i = 0; i < carousels.length; i++) { for (let i = 0; i < carousels.length; i++) {
let carousel = carousels[i] let carousel = carousels[i];
let items = carousel.getElementsByClassName('carousel-item') let items = carousel.getElementsByClassName("carousel-item");
let activeItem = 0 let activeItem = 0;
let autorotateTiming = carousel.getAttribute('data-autorotate') let autorotateTiming = carousel.getAttribute("data-autorotate");
// Generate bullets container // Generate bullets container
const bulletsContainer = document.createElement('div') const bulletsContainer = document.createElement("div");
bulletsContainer.className = 'carousel-bullets' bulletsContainer.className = "carousel-bullets";
carousel.parentNode.insertBefore(bulletsContainer, carousel.nextSibling) carousel.parentNode.insertBefore(bulletsContainer, carousel.nextSibling);
for (let i = 0; i < items.length; i++) { for (let i = 0; i < items.length; i++) {
// Add data attributes // Add data attributes
items[i].setAttribute('data-carousel', i) items[i].setAttribute("data-carousel", i);
// Determine a new active item, if any // Determine a new active item, if any
if (items[i].classList.contains('is-active')) activeItem = i if (items[i].classList.contains("is-active")) activeItem = i;
// Generate bullets // Generate bullets
let bullet = document.createElement('button') let bullet = document.createElement("button");
bullet.className = 'carousel-bullet' bullet.className = "carousel-bullet";
bullet.setAttribute('data-bullet', i) bullet.setAttribute("data-bullet", i);
carousel.parentNode.getElementsByClassName('carousel-bullets')[0].appendChild(bullet) carousel.parentNode
.getElementsByClassName("carousel-bullets")[0]
.appendChild(bullet);
} }
// Add is-active class to first carousel item and bullet // Add is-active class to first carousel item and bullet
items[activeItem].classList.add('is-active') items[activeItem].classList.add("is-active");
let bullets = carousel.parentNode.getElementsByClassName('carousel-bullet') let bullets = carousel.parentNode.getElementsByClassName(
bullets[activeItem].classList.add('is-active') "carousel-bullet"
);
bullets[activeItem].classList.add("is-active");
// Equal height items // Equal height items
equalHeightCarousel(carousel, items) equalHeightCarousel(carousel, items);
window.addEventListener('resize', function () { window.addEventListener("resize", function () {
equalHeightCarousel(carousel, items) equalHeightCarousel(carousel, items);
}) });
// Autorotate // Autorotate
let autorotate = false let autorotate = false;
if (autorotateTiming) { if (autorotateTiming) {
autorotate = setInterval(function () { autorotate = setInterval(function () {
rotateCarousel(carousel, 'next') rotateCarousel(carousel, "next");
}, autorotateTiming) }, autorotateTiming);
} }
// Rotate by bullet click // Rotate by bullet click
for (let i = 0; i < bullets.length; i++) { for (let i = 0; i < bullets.length; i++) {
let bullet = bullets[i] let bullet = bullets[i];
bullet.addEventListener('click', function (e) { bullet.addEventListener("click", function (e) {
e.preventDefault() e.preventDefault();
// Do nothing if item is active // Do nothing if item is active
if (bullet.classList.contains('is-active')) { if (bullet.classList.contains("is-active")) {
return return;
} }
// Remove active classes // Remove active classes
for (let i = 0; i < bullets.length; i++) { for (let i = 0; i < bullets.length; i++) {
bullets[i].classList.remove('is-active') bullets[i].classList.remove("is-active");
} }
for (let i = 0; i < items.length; i++) { for (let i = 0; i < items.length; i++) {
items[i].classList.remove('is-active') items[i].classList.remove("is-active");
} }
// Add active classes to corresponding items and bullets // Add active classes to corresponding items and bullets
let index = this.getAttribute('data-bullet') let index = this.getAttribute("data-bullet");
items[index].classList.add('is-active') items[index].classList.add("is-active");
this.classList.add('is-active') this.classList.add("is-active");
// Clear autorotate timing // Clear autorotate timing
clearAutorotate(autorotate) clearAutorotate(autorotate);
}) });
} }
// Rotate on swipe // Rotate on swipe
swipe.init(carousel, function (e) { swipe.init(carousel, function (e) {
if (e.direction === 'left') { if (e.direction === "left") {
rotateCarousel(carousel, 'next') rotateCarousel(carousel, "next");
} else if (e.direction === 'right') { } else if (e.direction === "right") {
rotateCarousel(carousel, 'prev') rotateCarousel(carousel, "prev");
} }
// Clear autorotate timing // Clear autorotate timing
clearAutorotate(autorotate) clearAutorotate(autorotate);
}) });
} }
} }
}()) })();

View File

@ -1,7 +1,7 @@
// Vars // Vars
const browserName = getBrowserName(); const browserName = getBrowserName();
const url = window.location.href; const url = window.location.href;
const roomHash = url.substring(url.lastIndexOf('/') + 1).toLowerCase(); const roomHash = url.substring(url.lastIndexOf("/") + 1).toLowerCase();
var mode = "camera"; var mode = "camera";
var isFullscreen = false; var isFullscreen = false;
var sendingCaptions = false; var sendingCaptions = false;
@ -14,18 +14,16 @@ const isWebRTCSupported =
window.RTCPeerConnection; window.RTCPeerConnection;
// Element vars // Element vars
const chatInput = document.querySelector('.compose textarea'); const chatInput = document.querySelector(".compose textarea");
const pipVideo = document.getElementById('remote-video'); const pipVideo = document.getElementById("remote-video");
var VideoChat = { var VideoChat = {
connected: false, connected: false,
willInitiateCall: false, willInitiateCall: false,
localICECandidates: [], localICECandidates: [],
socket: io(), socket: io(),
remoteVideo: document.getElementById('remote-video'), remoteVideo: document.getElementById("remote-video"),
localVideo: document.getElementById('local-video'), localVideo: document.getElementById("local-video"),
recognition: undefined, recognition: undefined,
// Call to getUserMedia (provided by adapter.js for cross browser compatibility) // Call to getUserMedia (provided by adapter.js for cross browser compatibility)
@ -35,77 +33,88 @@ var VideoChat = {
requestMediaStream: function (event) { requestMediaStream: function (event) {
logIt("requestMediaStream"); logIt("requestMediaStream");
rePositionLocalVideo(); rePositionLocalVideo();
navigator.mediaDevices.getUserMedia({ navigator.mediaDevices
.getUserMedia({
video: true, video: true,
audio: true audio: true,
}).then(stream => { })
.then((stream) => {
VideoChat.onMediaStream(stream); VideoChat.onMediaStream(stream);
$('#local-video-text').text("Drag Me"); $("#local-video-text").text("Drag Me");
setTimeout(() => $('#local-video-text').fadeOut(), 5000); setTimeout(() => $("#local-video-text").fadeOut(), 5000);
}).catch(error => { })
.catch((error) => {
logIt(error); logIt(error);
logIt('Failed to get local webcam video, check webcam privacy settings'); logIt(
"Failed to get local webcam video, check webcam privacy settings"
);
setTimeout(VideoChat.requestMediaStream, 1000); setTimeout(VideoChat.requestMediaStream, 1000);
}); });
}, },
// The onMediaStream function receives the media stream as an argument. // The onMediaStream function receives the media stream as an argument.
onMediaStream: function (stream) { onMediaStream: function (stream) {
logIt("onMediaStream"); logIt("onMediaStream");
VideoChat.localStream = stream; VideoChat.localStream = stream;
// Add the stream as video's srcObject. // Add the stream as video's srcObject.
Snackbar.show({ Snackbar.show({
text: 'Share this URL with a friend to get started', text: "Share this URL with a friend to get started",
actionText: 'Copy Link', actionText: "Copy Link",
width: '355px', width: "355px",
pos: 'top-center', pos: "top-center",
actionTextColor: '#8688ff', actionTextColor: "#8688ff",
duration: 500000, duration: 500000,
backgroundColor: '#16171a', backgroundColor: "#16171a",
onActionClick: function (element) { onActionClick: function (element) {
var copyContent = window.location.href; var copyContent = window.location.href;
$('<input id="some-element">').val(copyContent).appendTo('body').select(); $('<input id="some-element">')
document.execCommand('copy'); .val(copyContent)
var toRemove = document.querySelector('#some-element'); .appendTo("body")
.select();
document.execCommand("copy");
var toRemove = document.querySelector("#some-element");
toRemove.parentNode.removeChild(toRemove); toRemove.parentNode.removeChild(toRemove);
$(element).css('opacity', 0); //Set opacity of element to 0 to close Snackbar $(element).css("opacity", 0); //Set opacity of element to 0 to close Snackbar
} },
}); });
VideoChat.localVideo.srcObject = stream; VideoChat.localVideo.srcObject = stream;
// Now we're ready to join the chat room. // Now we're ready to join the chat room.
VideoChat.socket.emit('join', roomHash); VideoChat.socket.emit("join", roomHash);
VideoChat.socket.on('full', chatRoomFull); VideoChat.socket.on("full", chatRoomFull);
VideoChat.socket.on('offer', VideoChat.onOffer); VideoChat.socket.on("offer", VideoChat.onOffer);
VideoChat.socket.on('ready', VideoChat.readyToCall); VideoChat.socket.on("ready", VideoChat.readyToCall);
VideoChat.socket.on('willInitiateCall', () => VideoChat.willInitiateCall = true); VideoChat.socket.on(
"willInitiateCall",
() => (VideoChat.willInitiateCall = true)
);
}, },
// When we are ready to call, enable the Call button. // When we are ready to call, enable the Call button.
readyToCall: function (event) { readyToCall: function (event) {
logIt("readyToCall"); logIt("readyToCall");
if (VideoChat.willInitiateCall) { if (VideoChat.willInitiateCall) {
logIt("Initiating call") logIt("Initiating call");
VideoChat.startCall() VideoChat.startCall();
} }
}, },
// Set up a callback to run when we have the ephemeral token to use Twilio's TURN server. // Set up a callback to run when we have the ephemeral token to use Twilio's TURN server.
startCall: function (event) { startCall: function (event) {
logIt("startCall"); logIt("startCall");
logIt('>>> Sending token request...'); logIt(">>> Sending token request...");
VideoChat.socket.on('token', VideoChat.onToken(VideoChat.createOffer)); VideoChat.socket.on("token", VideoChat.onToken(VideoChat.createOffer));
VideoChat.socket.emit('token', roomHash); VideoChat.socket.emit("token", roomHash);
}, },
// When we receive the ephemeral token back from the server. // When we receive the ephemeral token back from the server.
onToken: function (callback) { onToken: function (callback) {
logIt("onToken"); logIt("onToken");
return function (token) { return function (token) {
logIt('<<< Received token'); logIt("<<< Received token");
// Set up a new RTCPeerConnection using the token's iceServers. // Set up a new RTCPeerConnection using the token's iceServers.
VideoChat.peerConnection = new RTCPeerConnection({iceServers: token.iceServers}); VideoChat.peerConnection = new RTCPeerConnection({
iceServers: token.iceServers,
});
// Add the local video stream to the peerConnection. // Add the local video stream to the peerConnection.
VideoChat.localStream.getTracks().forEach(function (track) { VideoChat.localStream.getTracks().forEach(function (track) {
VideoChat.peerConnection.addTrack(track, VideoChat.localStream); VideoChat.peerConnection.addTrack(track, VideoChat.localStream);
@ -116,10 +125,12 @@ var VideoChat = {
VideoChat.peerConnection.onaddstream = VideoChat.onAddStream; VideoChat.peerConnection.onaddstream = VideoChat.onAddStream;
// Set up listeners on the socket for candidates or answers being passed // Set up listeners on the socket for candidates or answers being passed
// over the socket connection. // over the socket connection.
VideoChat.socket.on('candidate', VideoChat.onCandidate); VideoChat.socket.on("candidate", VideoChat.onCandidate);
VideoChat.socket.on('answer', VideoChat.onAnswer); VideoChat.socket.on("answer", VideoChat.onAnswer);
VideoChat.socket.on('requestToggleCaptions', () => toggleSendCaptions()); VideoChat.socket.on("requestToggleCaptions", () => toggleSendCaptions());
VideoChat.socket.on('recieveCaptions', (captions) => recieveCaptions(captions)); VideoChat.socket.on("recieveCaptions", (captions) =>
recieveCaptions(captions)
);
callback(); callback();
}; };
@ -129,10 +140,16 @@ var VideoChat = {
onIceCandidate: function (event) { onIceCandidate: function (event) {
logIt("onIceCandidate"); logIt("onIceCandidate");
if (event.candidate) { if (event.candidate) {
logIt(`<<< Received local ICE candidate from STUN/TURN server (${event.candidate.address})`); logIt(
`<<< Received local ICE candidate from STUN/TURN server (${event.candidate.address})`
);
if (VideoChat.connected) { if (VideoChat.connected) {
logIt(`>>> Sending local ICE candidate (${event.candidate.address})`); logIt(`>>> Sending local ICE candidate (${event.candidate.address})`);
VideoChat.socket.emit('candidate', JSON.stringify(event.candidate), roomHash); VideoChat.socket.emit(
"candidate",
JSON.stringify(event.candidate),
roomHash
);
} else { } else {
// If we are not 'connected' to the other peer, we are buffering the local ICE candidates. // If we are not 'connected' to the other peer, we are buffering the local ICE candidates.
// This most likely is happening on the "caller" side. // This most likely is happening on the "caller" side.
@ -148,21 +165,23 @@ var VideoChat = {
onCandidate: function (candidate) { onCandidate: function (candidate) {
logIt("onCandidate"); logIt("onCandidate");
rtcCandidate = new RTCIceCandidate(JSON.parse(candidate)); rtcCandidate = new RTCIceCandidate(JSON.parse(candidate));
logIt(`<<< Received remote ICE candidate (${rtcCandidate.address} - ${rtcCandidate.relatedAddress})`); logIt(
`<<< Received remote ICE candidate (${rtcCandidate.address} - ${rtcCandidate.relatedAddress})`
);
VideoChat.peerConnection.addIceCandidate(rtcCandidate); VideoChat.peerConnection.addIceCandidate(rtcCandidate);
}, },
// Create an offer that contains the media capabilities of the browser. // Create an offer that contains the media capabilities of the browser.
createOffer: function () { createOffer: function () {
logIt("createOffer"); logIt("createOffer");
logIt('>>> Creating offer...'); logIt(">>> Creating offer...");
VideoChat.peerConnection.createOffer( VideoChat.peerConnection.createOffer(
function (offer) { function (offer) {
// If the offer is created successfully, set it as the local description // If the offer is created successfully, set it as the local description
// and send it over the socket connection to initiate the peerConnection // and send it over the socket connection to initiate the peerConnection
// on the other side. // on the other side.
VideoChat.peerConnection.setLocalDescription(offer); VideoChat.peerConnection.setLocalDescription(offer);
VideoChat.socket.emit('offer', JSON.stringify(offer), roomHash); VideoChat.socket.emit("offer", JSON.stringify(offer), roomHash);
}, },
function (err) { function (err) {
logIt("failed offer creation"); logIt("failed offer creation");
@ -179,13 +198,13 @@ var VideoChat = {
createAnswer: function (offer) { createAnswer: function (offer) {
logIt("createAnswer"); logIt("createAnswer");
return function () { return function () {
logIt('>>> Creating answer...'); logIt(">>> Creating answer...");
rtcOffer = new RTCSessionDescription(JSON.parse(offer)); rtcOffer = new RTCSessionDescription(JSON.parse(offer));
VideoChat.peerConnection.setRemoteDescription(rtcOffer); VideoChat.peerConnection.setRemoteDescription(rtcOffer);
VideoChat.peerConnection.createAnswer( VideoChat.peerConnection.createAnswer(
function (answer) { function (answer) {
VideoChat.peerConnection.setLocalDescription(answer); VideoChat.peerConnection.setLocalDescription(answer);
VideoChat.socket.emit('answer', JSON.stringify(answer), roomHash); VideoChat.socket.emit("answer", JSON.stringify(answer), roomHash);
}, },
function (err) { function (err) {
logIt("Failed answer creation."); logIt("Failed answer creation.");
@ -199,22 +218,25 @@ var VideoChat = {
// ephemeral token is returned from Twilio. // ephemeral token is returned from Twilio.
onOffer: function (offer) { onOffer: function (offer) {
logIt("onOffer"); logIt("onOffer");
logIt('<<< Received offer'); logIt("<<< Received offer");
VideoChat.socket.on('token', VideoChat.onToken(VideoChat.createAnswer(offer))); VideoChat.socket.on(
VideoChat.socket.emit('token', roomHash); "token",
VideoChat.onToken(VideoChat.createAnswer(offer))
);
VideoChat.socket.emit("token", roomHash);
}, },
// When an answer is received, add it to the peerConnection as the remote description. // When an answer is received, add it to the peerConnection as the remote description.
onAnswer: function (answer) { onAnswer: function (answer) {
logIt("onAnswer"); logIt("onAnswer");
logIt('<<< Received answer'); logIt("<<< Received answer");
var rtcAnswer = new RTCSessionDescription(JSON.parse(answer)); var rtcAnswer = new RTCSessionDescription(JSON.parse(answer));
VideoChat.peerConnection.setRemoteDescription(rtcAnswer); VideoChat.peerConnection.setRemoteDescription(rtcAnswer);
VideoChat.localICECandidates.forEach(candidate => { VideoChat.localICECandidates.forEach((candidate) => {
// The caller now knows that the callee is ready to accept new ICE candidates, so sending the buffer over // The caller now knows that the callee is ready to accept new ICE candidates, so sending the buffer over
logIt(`>>> Sending local ICE candidate (${candidate.address})`); logIt(`>>> Sending local ICE candidate (${candidate.address})`);
VideoChat.socket.emit('candidate', JSON.stringify(candidate), roomHash); VideoChat.socket.emit("candidate", JSON.stringify(candidate), roomHash);
}); });
// Reset the buffer of local ICE candidates. This is not really needed, but it's good practice // Reset the buffer of local ICE candidates. This is not really needed, but it's good practice
VideoChat.localICECandidates = []; VideoChat.localICECandidates = [];
@ -222,13 +244,13 @@ var VideoChat = {
onAddStream: function (event) { onAddStream: function (event) {
logIt("onAddStream"); logIt("onAddStream");
logIt('<<< Received new stream from remote. Adding it...'); logIt("<<< Received new stream from remote. Adding it...");
VideoChat.remoteVideo.srcObject = event.stream; VideoChat.remoteVideo.srcObject = event.stream;
Snackbar.close(); Snackbar.close();
VideoChat.remoteVideo.style.background = 'none'; VideoChat.remoteVideo.style.background = "none";
VideoChat.connected = true; VideoChat.connected = true;
$('#remote-video-text').fadeOut(); $("#remote-video-text").fadeOut();
$('#local-video-text').fadeOut(); $("#local-video-text").fadeOut();
var timesRun = 0; var timesRun = 0;
var interval = setInterval(function () { var interval = setInterval(function () {
@ -236,12 +258,11 @@ var VideoChat = {
if (timesRun === 20) { if (timesRun === 20) {
clearInterval(interval); clearInterval(interval);
} }
rePositionLocalVideo() rePositionLocalVideo();
}, 300); }, 300);
}, },
}; };
function getBrowserName() { function getBrowserName() {
var name = "Unknown"; var name = "Unknown";
if (window.navigator.userAgent.indexOf("MSIE") !== -1) { if (window.navigator.userAgent.indexOf("MSIE") !== -1) {
@ -262,7 +283,9 @@ function logIt(message, error) {
} }
function chatRoomFull() { function chatRoomFull() {
alert("Chat room is full. Check to make sure you don't have multiple open tabs, or try with a new room link"); alert(
"Chat room is full. Check to make sure you don't have multiple open tabs, or try with a new room link"
);
window.location.href = "/newroom"; window.location.href = "/newroom";
} }
@ -270,37 +293,41 @@ function rePositionLocalVideo() {
var bounds = $("#remote-video").position(); var bounds = $("#remote-video").position();
bounds.top += 10; bounds.top += 10;
bounds.left += 10; bounds.left += 10;
$("#moveable").css(bounds) $("#moveable").css(bounds);
} }
// //
// Fullscreen // Fullscreen
// //
function openFullscreen() { function openFullscreen() {
var elem = document.getElementById("remote-video"); var elem = document.getElementById("remote-video");
if (!isFullscreen) { if (!isFullscreen) {
isFullscreen = true; isFullscreen = true;
if (elem.requestFullscreen) { if (elem.requestFullscreen) {
elem.requestFullscreen(); elem.requestFullscreen();
} else if (elem.mozRequestFullScreen) { /* Firefox */ } else if (elem.mozRequestFullScreen) {
/* Firefox */
elem.mozRequestFullScreen(); elem.mozRequestFullScreen();
} else if (elem.webkitRequestFullscreen) { /* Chrome, Safari and Opera */ } else if (elem.webkitRequestFullscreen) {
/* Chrome, Safari and Opera */
elem.webkitRequestFullscreen(); elem.webkitRequestFullscreen();
} else if (elem.msRequestFullscreen) { /* IE/Edge */ } else if (elem.msRequestFullscreen) {
/* IE/Edge */
elem.msRequestFullscreen(); elem.msRequestFullscreen();
} }
} else { } else {
isFullscreen = false; isFullscreen = false;
if (document.exitFullscreen) { if (document.exitFullscreen) {
document.exitFullscreen(); document.exitFullscreen();
} else if (document.mozCancelFullScreen) { /* Firefox */ } else if (document.mozCancelFullScreen) {
/* Firefox */
document.mozCancelFullScreen(); document.mozCancelFullScreen();
} else if (document.webkitExitFullscreen) { /* Chrome, Safari and Opera */ } else if (document.webkitExitFullscreen) {
/* Chrome, Safari and Opera */
document.webkitExitFullscreen(); document.webkitExitFullscreen();
} else if (document.msExitFullscreen) { /* IE/Edge */ } else if (document.msExitFullscreen) {
/* IE/Edge */
document.msExitFullscreen(); document.msExitFullscreen();
} }
} }
@ -310,7 +337,6 @@ function openFullscreen() {
// End Fullscreen // End Fullscreen
// //
// //
// Mute microphone // Mute microphone
// //
@ -322,11 +348,11 @@ function muteMicrophone() {
if (muted) { if (muted) {
micIcon.classList.remove("fa-microphone"); micIcon.classList.remove("fa-microphone");
micIcon.classList.add("fa-microphone-slash"); micIcon.classList.add("fa-microphone-slash");
micText.innerText = "Unmute" micText.innerText = "Unmute";
} else { } else {
micIcon.classList.add("fa-microphone"); micIcon.classList.add("fa-microphone");
micIcon.classList.remove("fa-microphone-slash"); micIcon.classList.remove("fa-microphone-slash");
micText.innerText = "Mute" micText.innerText = "Mute";
} }
} }
@ -345,11 +371,11 @@ function pauseVideo() {
if (paused) { if (paused) {
micIcon.classList.remove("fa-video"); micIcon.classList.remove("fa-video");
micIcon.classList.add("fa-video-slash"); micIcon.classList.add("fa-video-slash");
micText.innerText = "Unpause Video" micText.innerText = "Unpause Video";
} else { } else {
micIcon.classList.add("fa-video"); micIcon.classList.add("fa-video");
micIcon.classList.remove("fa-video-slash"); micIcon.classList.remove("fa-video-slash");
micText.innerText = "Pause Video" micText.innerText = "Pause Video";
} }
} }
@ -357,7 +383,6 @@ function pauseVideo() {
// End pause Video // End pause Video
// //
// //
// Swap camera / screen share // Swap camera / screen share
// //
@ -365,15 +390,17 @@ function pauseVideo() {
function swap() { function swap() {
if (!VideoChat.connected) { if (!VideoChat.connected) {
alert("You must join a call before you can share your screen."); alert("You must join a call before you can share your screen.");
return return;
} }
const swapIcon = document.getElementById("swap-icon"); const swapIcon = document.getElementById("swap-icon");
const swapText = document.getElementById("swap-text"); const swapText = document.getElementById("swap-text");
if (mode === "camera") { if (mode === "camera") {
navigator.mediaDevices.getDisplayMedia({ navigator.mediaDevices
.getDisplayMedia({
video: true, video: true,
audio: true audio: true,
}).then(function (stream) { })
.then(function (stream) {
mode = "screen"; mode = "screen";
swapIcon.classList.remove("fa-desktop"); swapIcon.classList.remove("fa-desktop");
swapIcon.classList.add("fa-camera"); swapIcon.classList.add("fa-camera");
@ -381,11 +408,13 @@ function swap() {
switchStreamHelper(stream); switchStreamHelper(stream);
}); });
} else { } else {
VideoChat.localVideo.srcObject.getTracks().forEach(track => track.stop()); VideoChat.localVideo.srcObject.getTracks().forEach((track) => track.stop());
navigator.mediaDevices.getUserMedia({ navigator.mediaDevices
.getUserMedia({
video: true, video: true,
audio: true audio: true,
}).then(function (stream) { })
.then(function (stream) {
mode = "camera"; mode = "camera";
swapIcon.classList.remove("fa-camera"); swapIcon.classList.remove("fa-camera");
swapIcon.classList.add("fa-desktop"); swapIcon.classList.add("fa-desktop");
@ -411,7 +440,6 @@ function switchStreamHelper(stream) {
// End swap camera / screen share // End swap camera / screen share
// //
// //
// Live caption // Live caption
// //
@ -419,18 +447,20 @@ function switchStreamHelper(stream) {
function requestToggleCaptions() { function requestToggleCaptions() {
if (!VideoChat.connected) { if (!VideoChat.connected) {
alert("You must be connected to a peer to use Live Caption"); alert("You must be connected to a peer to use Live Caption");
return return;
} }
if (receivingCaptions) { if (receivingCaptions) {
$('#remote-video-text').text("").fadeOut(); $("#remote-video-text").text("").fadeOut();
$('#caption-text').text("Start Live Caption"); $("#caption-text").text("Start Live Caption");
receivingCaptions = false; receivingCaptions = false;
} else { } else {
alert("This is an expirimental feature. Live transcription requires the other user to have chrome."); alert(
$('#caption-text').text("End Live Caption"); "This is an expirimental feature. Live transcription requires the other user to have chrome."
);
$("#caption-text").text("End Live Caption");
receivingCaptions = true; receivingCaptions = true;
} }
VideoChat.socket.emit('requestToggleCaptions', roomHash); VideoChat.socket.emit("requestToggleCaptions", roomHash);
} }
function toggleSendCaptions() { function toggleSendCaptions() {
@ -445,15 +475,16 @@ function toggleSendCaptions() {
function startSpeech() { function startSpeech() {
try { try {
var SpeechRecognition = window.SpeechRecognition || window.webkitSpeechRecognition; var SpeechRecognition =
window.SpeechRecognition || window.webkitSpeechRecognition;
var recognition = new SpeechRecognition(); var recognition = new SpeechRecognition();
VideoChat.recognition = recognition; VideoChat.recognition = recognition;
} catch (e) { } catch (e) {
sendingCaptions = false; sendingCaptions = false;
logIt(e); logIt(e);
logIt("error importing speech library"); logIt("error importing speech library");
VideoChat.socket.emit('sendCaptions', "notusingchrome", roomHash); VideoChat.socket.emit("sendCaptions", "notusingchrome", roomHash);
return return;
} }
// If false, the recording will stop after a few seconds of silence. // If false, the recording will stop after a few seconds of silence.
@ -465,14 +496,14 @@ function startSpeech() {
var finalTranscript; var finalTranscript;
recognition.onresult = (event) => { recognition.onresult = (event) => {
let interimTranscript = ''; let interimTranscript = "";
for (let i = event.resultIndex, len = event.results.length; i < len; i++) { for (let i = event.resultIndex, len = event.results.length; i < len; i++) {
let transcript = event.results[i][0].transcript; let transcript = event.results[i][0].transcript;
if (event.results[i].isFinal) { if (event.results[i].isFinal) {
finalTranscript += transcript; finalTranscript += transcript;
} else { } else {
interimTranscript += transcript; interimTranscript += transcript;
VideoChat.socket.emit('sendCaptions', interimTranscript, roomHash); VideoChat.socket.emit("sendCaptions", interimTranscript, roomHash);
// console.log(interimTranscript); // console.log(interimTranscript);
} }
} }
@ -487,7 +518,7 @@ function startSpeech() {
}; };
recognition.onerror = function (event) { recognition.onerror = function (event) {
if (event.error === 'no-speech') { if (event.error === "no-speech") {
console.log("no speech detected"); console.log("no speech detected");
} }
}; };
@ -496,7 +527,7 @@ function startSpeech() {
console.log("on end"); console.log("on end");
console.log(sendingCaptions); console.log(sendingCaptions);
if (sendingCaptions) { if (sendingCaptions) {
startSpeech() startSpeech();
} else { } else {
VideoChat.recognition.stop(); VideoChat.recognition.stop();
} }
@ -506,21 +537,21 @@ function startSpeech() {
} }
function recieveCaptions(captions) { function recieveCaptions(captions) {
$('#remote-video-text').text("").fadeIn(); $("#remote-video-text").text("").fadeIn();
if (!receivingCaptions) { if (!receivingCaptions) {
$('#remote-video-text').text("").fadeOut(); $("#remote-video-text").text("").fadeOut();
} }
if (captions === "notusingchrome") { if (captions === "notusingchrome") {
alert("Other caller must be using chrome for this feature to work"); alert("Other caller must be using chrome for this feature to work");
receivingCaptions = false; receivingCaptions = false;
$('#remote-video-text').text("").fadeOut(); $("#remote-video-text").text("").fadeOut();
$('#caption-text').text("Start Live Caption"); $("#caption-text").text("Start Live Caption");
return return;
} }
if (captions.length > 100) { if (captions.length > 100) {
$('#remote-video-text').text(captions.substr(captions.length - 199)); $("#remote-video-text").text(captions.substr(captions.length - 199));
} else { } else {
$('#remote-video-text').text(captions); $("#remote-video-text").text(captions);
} }
} }
@ -534,30 +565,36 @@ function recieveCaptions(captions) {
var socket = VideoChat.socket; var socket = VideoChat.socket;
chatInput.addEventListener('keypress', function (event) { chatInput.addEventListener("keypress", function (event) {
if (event.keyCode === 13) { if (event.keyCode === 13) {
event.preventDefault(); event.preventDefault();
socket.emit('chat message', chatInput.value, roomHash); socket.emit("chat message", chatInput.value, roomHash);
$('.chat-messages').append('<div class="message-item customer"><div class="message-bloc"><div class="message">' + chatInput.value + '</div></div></div>'); $(".chat-messages").append(
$('#chat-zone').scrollTop($('#chat-zone')[0].scrollHeight); '<div class="message-item customer"><div class="message-bloc"><div class="message">' +
chatInput.value = ''; chatInput.value +
"</div></div></div>"
);
$("#chat-zone").scrollTop($("#chat-zone")[0].scrollHeight);
chatInput.value = "";
} }
}); });
socket.on("chat message", function (msg) {
socket.on('chat message', function (msg) { $(".chat-messages").append(
$('.chat-messages').append('<div class="message-item moderator"><div class="message-bloc"><div class="message">' + msg + '</div></div></div>'); '<div class="message-item moderator"><div class="message-bloc"><div class="message">' +
$('#chat-zone').scrollTop($('#chat-zone')[0].scrollHeight); msg +
if ($('#entire-chat').is(":hidden")) { "</div></div></div>"
toggleChat() );
$("#chat-zone").scrollTop($("#chat-zone")[0].scrollHeight);
if ($("#entire-chat").is(":hidden")) {
toggleChat();
} }
}); });
function toggleChat() { function toggleChat() {
var entireChat = $('#entire-chat'); var entireChat = $("#entire-chat");
var chatIcon = document.getElementById("chat-icon"); var chatIcon = document.getElementById("chat-icon");
var chatText = $('#chat-text'); var chatText = $("#chat-text");
if (entireChat.is(":visible")) { if (entireChat.is(":visible")) {
entireChat.fadeOut(); entireChat.fadeOut();
chatText.text("Show Chat"); chatText.text("Show Chat");
@ -580,42 +617,40 @@ function toggleChat() {
// //
function togglePictureInPicture() { function togglePictureInPicture() {
if ('pictureInPictureEnabled' in document) { if ("pictureInPictureEnabled" in document) {
if (document.pictureInPictureElement) { if (document.pictureInPictureElement) {
document.exitPictureInPicture() document.exitPictureInPicture().catch((error) => {
.catch(error => {
logIt("Error exiting pip."); logIt("Error exiting pip.");
logIt(error); logIt(error);
}); });
} else { } else {
pipVideo.requestPictureInPicture() pipVideo.requestPictureInPicture().catch((error) => {
.catch(error => {
logIt("Error entering pip."); logIt("Error entering pip.");
logIt(error); logIt(error);
}); });
} }
} else { } else {
alert("Picture in picture is not supported in your browser. Consider using Chrome.") alert(
"Picture in picture is not supported in your browser. Consider using Chrome."
);
} }
} }
pipVideo.addEventListener("enterpictureinpicture", () => {
pipVideo.addEventListener('enterpictureinpicture', () => { $("#pip-text").text("Exit Picture in Picture");
$('#pip-text').text("Exit Picture in Picture");
}); });
pipVideo.addEventListener('leavepictureinpicture', () => { pipVideo.addEventListener("leavepictureinpicture", () => {
$('#pip-text').text("Enter Picture in Picture"); $("#pip-text").text("Enter Picture in Picture");
}); });
// //
//Picture in picture //Picture in picture
// //
function startUp() { function startUp() {
// strip url parameters // strip url parameters
if (url.indexOf('?') > -1) { if (url.indexOf("?") > -1) {
window.location.href = url.split('?')[0]; window.location.href = url.split("?")[0];
} }
// if no chat room provided go back to newroom // if no chat room provided go back to newroom
@ -624,23 +659,29 @@ function startUp() {
} }
// Redirect unsupported browsers // Redirect unsupported browsers
if (!isWebRTCSupported || browserName === "Safari" || browserName === "MSIE") { if (
alert("Your browser doesn't support Neon Chat. Please use Chrome or Firefox."); !isWebRTCSupported ||
browserName === "Safari" ||
browserName === "MSIE"
) {
alert(
"Your browser doesn't support Neon Chat. Please use Chrome or Firefox."
);
window.location.href = "/"; window.location.href = "/";
} }
document.title = 'Neon Chat - ' + url.substring(url.lastIndexOf('/') + 1); document.title = "Neon Chat - " + url.substring(url.lastIndexOf("/") + 1);
// get webcam on load // get webcam on load
VideoChat.requestMediaStream(); VideoChat.requestMediaStream();
$('#remote-video-text').text("").fadeOut(); $("#remote-video-text").text("").fadeOut();
$("#moveable").draggable({containment: 'window'}); $("#moveable").draggable({ containment: "window" });
$(".HoverState").hide(); $(".HoverState").hide();
$('#entire-chat').hide(); $("#entire-chat").hide();
// //
// Show hide button labels on hover // Show hide button labels on hover
@ -660,7 +701,6 @@ function startUp() {
// End show hide button labels on hover // End show hide button labels on hover
// //
// //
// Fade out / show UI on mouse move // Fade out / show UI on mouse move
// //
@ -669,16 +709,16 @@ function startUp() {
function delayCheck() { function delayCheck() {
if (timedelay === 5) { if (timedelay === 5) {
$('.multi-button').fadeOut(); $(".multi-button").fadeOut();
$('#header').fadeOut(); $("#header").fadeOut();
timedelay = 1; timedelay = 1;
} }
timedelay = timedelay + 1; timedelay = timedelay + 1;
} }
$(document).mousemove(function () { $(document).mousemove(function () {
$('.multi-button').fadeIn(); $(".multi-button").fadeIn();
$('#header').fadeIn(); $("#header").fadeIn();
timedelay = 1; timedelay = 1;
clearInterval(_delay); clearInterval(_delay);
_delay = setInterval(delayCheck, 500); _delay = setInterval(delayCheck, 500);
@ -691,16 +731,19 @@ function startUp() {
// Show accept webcam snackbar // Show accept webcam snackbar
Snackbar.show({ Snackbar.show({
text: 'Please allow microphone and webcam access', text: "Please allow microphone and webcam access",
actionText: 'Show Me How', actionText: "Show Me How",
width: '455px', width: "455px",
pos: 'top-right', pos: "top-right",
actionTextColor: '#8688ff', actionTextColor: "#8688ff",
duration: 50000, duration: 50000,
backgroundColor: '#292B32', backgroundColor: "#292B32",
onActionClick: function (element) { onActionClick: function (element) {
window.open('https://getacclaim.zendesk.com/hc/en-us/articles/360001547832-Setting-the-default-camera-on-your-browser', '_blank'); window.open(
} "https://getacclaim.zendesk.com/hc/en-us/articles/360001547832-Setting-the-default-camera-on-your-browser",
"_blank"
);
},
}); });
} }

View File

@ -1,137 +1,250 @@
!function () { !(function () {
"use strict"; "use strict";
const e = document.getElementsByClassName("accordion-header"); const e = document.getElementsByClassName("accordion-header");
function t(e, t) { function t(e, t) {
e.classList.add("is-active"), t.style.maxHeight = t.scrollHeight + "px" e.classList.add("is-active"), (t.style.maxHeight = t.scrollHeight + "px");
} }
function n(e, t) { function n(e, t) {
e.classList.remove("is-active"), t.style.maxHeight = null e.classList.remove("is-active"), (t.style.maxHeight = null);
} }
if (e.length > 0) for (let i = 0; i < e.length; i++) { if (e.length > 0)
const s = e[i], a = s.parentNode, l = s.nextElementSibling; for (let i = 0; i < e.length; i++) {
a.classList.contains("is-active") && t(a, l), s.addEventListener("click", function () { const s = e[i],
a.classList.contains("is-active") ? n(a, l) : t(a, l) a = s.parentNode,
}) l = s.nextElementSibling;
a.classList.contains("is-active") && t(a, l),
s.addEventListener("click", function () {
a.classList.contains("is-active") ? n(a, l) : t(a, l);
});
} }
}(), function () { })(),
(function () {
"use strict"; "use strict";
let e = { let e = {
touchStartX: 0, touchEndX: 0, minSwipePixels: 30, detectionZone: void 0, swipeCallback: function () { touchStartX: 0,
}, init: function (t, n) { touchEndX: 0,
e.swipeCallback = n, t.addEventListener("touchstart", function (t) { minSwipePixels: 30,
e.touchStartX = t.changedTouches[0].screenX detectionZone: void 0,
}, !1), t.addEventListener("touchend", function (t) { swipeCallback: function () {},
e.touchEndX = t.changedTouches[0].screenX, e.handleSwipeGesture() init: function (t, n) {
}, !1) (e.swipeCallback = n),
}, handleSwipeGesture: function () { t.addEventListener(
"touchstart",
function (t) {
e.touchStartX = t.changedTouches[0].screenX;
},
!1
),
t.addEventListener(
"touchend",
function (t) {
(e.touchEndX = t.changedTouches[0].screenX),
e.handleSwipeGesture();
},
!1
);
},
handleSwipeGesture: function () {
let t, n; let t, n;
e.touchEndX <= e.touchStartX && (n = e.touchStartX - e.touchEndX, t = "left"), e.touchEndX >= e.touchStartX && (n = e.touchEndX - e.touchStartX, t = "right"), n > e.minSwipePixels && "undefined" !== t && e.swipe(t, n) e.touchEndX <= e.touchStartX &&
}, swipe: function (t, n) { ((n = e.touchStartX - e.touchEndX), (t = "left")),
e.touchEndX >= e.touchStartX &&
((n = e.touchEndX - e.touchStartX), (t = "right")),
n > e.minSwipePixels && "undefined" !== t && e.swipe(t, n);
},
swipe: function (t, n) {
let i = {}; let i = {};
i.direction = t, i.movedPixels = n, e.swipeCallback(i) (i.direction = t), (i.movedPixels = n), e.swipeCallback(i);
} },
}; };
const t = document.getElementsByClassName("carousel-items"); const t = document.getElementsByClassName("carousel-items");
function n(e, t) { function n(e, t) {
void 0 === t && (t = "next"); void 0 === t && (t = "next");
let n = e.getElementsByClassName("carousel-item is-active")[0], let n = e.getElementsByClassName("carousel-item is-active")[0],
i = "next" === t ? n.nextElementSibling : n.previousElementSibling, s = n.getAttribute("data-carousel"), i = "next" === t ? n.nextElementSibling : n.previousElementSibling,
s = n.getAttribute("data-carousel"),
a = e.parentNode.getElementsByClassName("carousel-bullet")[s], a = e.parentNode.getElementsByClassName("carousel-bullet")[s],
l = "next" === t ? a.nextElementSibling : a.previousElementSibling; l = "next" === t ? a.nextElementSibling : a.previousElementSibling;
n.classList.remove("is-active"), a.classList.remove("is-active"), i ? (i.classList.add("is-active"), l.classList.add("is-active")) : "next" === t ? (e.firstElementChild.classList.add("is-active"), e.parentNode.getElementsByClassName("carousel-bullets")[0].firstElementChild.classList.add("is-active")) : (e.lastElementChild.classList.add("is-active"), e.parentNode.getElementsByClassName("carousel-bullets")[0].lastElementChild.classList.add("is-active")) n.classList.remove("is-active"),
a.classList.remove("is-active"),
i
? (i.classList.add("is-active"), l.classList.add("is-active"))
: "next" === t
? (e.firstElementChild.classList.add("is-active"),
e.parentNode
.getElementsByClassName("carousel-bullets")[0]
.firstElementChild.classList.add("is-active"))
: (e.lastElementChild.classList.add("is-active"),
e.parentNode
.getElementsByClassName("carousel-bullets")[0]
.lastElementChild.classList.add("is-active"));
} }
function i(e, t) { function i(e, t) {
let n, i = 0; let n,
for (let e = 0; e < t.length; e++) t[0].parentNode.style.minHeight = i + "px", t[e].classList.add("is-loading"), n = t[e].offsetHeight, t[e].classList.remove("is-loading"), n > i && (i = n); i = 0;
t[0].parentNode.style.minHeight = i + "px" for (let e = 0; e < t.length; e++)
(t[0].parentNode.style.minHeight = i + "px"),
t[e].classList.add("is-loading"),
(n = t[e].offsetHeight),
t[e].classList.remove("is-loading"),
n > i && (i = n);
t[0].parentNode.style.minHeight = i + "px";
} }
function s(e) { function s(e) {
e && clearInterval(e) e && clearInterval(e);
} }
if (t.length > 0) for (let a = 0; a < t.length; a++) { if (t.length > 0)
let l = t[a], c = l.getElementsByClassName("carousel-item"), o = 0, r = l.getAttribute("data-autorotate"); for (let a = 0; a < t.length; a++) {
let l = t[a],
c = l.getElementsByClassName("carousel-item"),
o = 0,
r = l.getAttribute("data-autorotate");
const d = document.createElement("div"); const d = document.createElement("div");
d.className = "carousel-bullets", l.parentNode.insertBefore(d, l.nextSibling); (d.className = "carousel-bullets"),
l.parentNode.insertBefore(d, l.nextSibling);
for (let e = 0; e < c.length; e++) { for (let e = 0; e < c.length; e++) {
c[e].setAttribute("data-carousel", e), c[e].classList.contains("is-active") && (o = e); c[e].setAttribute("data-carousel", e),
c[e].classList.contains("is-active") && (o = e);
let t = document.createElement("button"); let t = document.createElement("button");
t.className = "carousel-bullet", t.setAttribute("data-bullet", e), l.parentNode.getElementsByClassName("carousel-bullets")[0].appendChild(t) (t.className = "carousel-bullet"),
t.setAttribute("data-bullet", e),
l.parentNode
.getElementsByClassName("carousel-bullets")[0]
.appendChild(t);
} }
c[o].classList.add("is-active"); c[o].classList.add("is-active");
let u = l.parentNode.getElementsByClassName("carousel-bullet"); let u = l.parentNode.getElementsByClassName("carousel-bullet");
u[o].classList.add("is-active"), i(0, c), window.addEventListener("resize", function () { u[o].classList.add("is-active"),
i(0, c) i(0, c),
window.addEventListener("resize", function () {
i(0, c);
}); });
let m = !1; let m = !1;
r && (m = setInterval(function () { r &&
n(l, "next") (m = setInterval(function () {
n(l, "next");
}, r)); }, r));
for (let e = 0; e < u.length; e++) { for (let e = 0; e < u.length; e++) {
let t = u[e]; let t = u[e];
t.addEventListener("click", function (e) { t.addEventListener("click", function (e) {
if (e.preventDefault(), t.classList.contains("is-active")) return; if ((e.preventDefault(), t.classList.contains("is-active"))) return;
for (let e = 0; e < u.length; e++) u[e].classList.remove("is-active"); for (let e = 0; e < u.length; e++)
for (let e = 0; e < c.length; e++) c[e].classList.remove("is-active"); u[e].classList.remove("is-active");
for (let e = 0; e < c.length; e++)
c[e].classList.remove("is-active");
let n = this.getAttribute("data-bullet"); let n = this.getAttribute("data-bullet");
c[n].classList.add("is-active"), this.classList.add("is-active"), s(m) c[n].classList.add("is-active"),
}) this.classList.add("is-active"),
s(m);
});
} }
e.init(l, function (e) { e.init(l, function (e) {
"left" === e.direction ? n(l, "next") : "right" === e.direction && n(l, "prev"), s(m) "left" === e.direction
}) ? n(l, "next")
: "right" === e.direction && n(l, "prev"),
s(m);
});
} }
}(), function () { })(),
(function () {
"use strict"; "use strict";
document.documentElement.classList.remove("no-js"), document.documentElement.classList.add("js"), window.addEventListener("load", function () { document.documentElement.classList.remove("no-js"),
document.body.classList.add("is-loaded") document.documentElement.classList.add("js"),
}) window.addEventListener("load", function () {
}(), function () { document.body.classList.add("is-loaded");
});
})(),
(function () {
"use strict"; "use strict";
const e = document.getElementById("header-nav-toggle"), t = document.getElementById("header-nav"); const e = document.getElementById("header-nav-toggle"),
e && (e.addEventListener("click", function () { t = document.getElementById("header-nav");
document.body.classList.toggle("off-nav-is-active"), t.classList.toggle("is-active"), t.style.maxHeight ? t.style.maxHeight = null : t.style.maxHeight = t.scrollHeight + "px", "true" === this.getAttribute("aria-expanded") ? this.setAttribute("aria-expanded", "false") : this.setAttribute("aria-expanded", "true") e &&
}), document.addEventListener("click", function (n) { (e.addEventListener("click", function () {
n.target === t || n.target === e || t.contains(n.target) || (document.body.classList.remove("off-nav-is-active"), t.classList.remove("is-active"), t.style.maxHeight = null, e.setAttribute("aria-expanded", "false")) document.body.classList.toggle("off-nav-is-active"),
})) t.classList.toggle("is-active"),
}(), function () { t.style.maxHeight
? (t.style.maxHeight = null)
: (t.style.maxHeight = t.scrollHeight + "px"),
"true" === this.getAttribute("aria-expanded")
? this.setAttribute("aria-expanded", "false")
: this.setAttribute("aria-expanded", "true");
}),
document.addEventListener("click", function (n) {
n.target === t ||
n.target === e ||
t.contains(n.target) ||
(document.body.classList.remove("off-nav-is-active"),
t.classList.remove("is-active"),
(t.style.maxHeight = null),
e.setAttribute("aria-expanded", "false"));
}));
})(),
(function () {
"use strict"; "use strict";
const e = document.getElementsByClassName("modal"), t = document.getElementsByClassName("modal-trigger"); const e = document.getElementsByClassName("modal"),
t = document.getElementsByClassName("modal-trigger");
function n() { function n() {
document.body.classList.remove("modal-is-active"); document.body.classList.remove("modal-is-active");
for (let t = 0; t < e.length; t++) e[t].classList.remove("is-active") for (let t = 0; t < e.length; t++) e[t].classList.remove("is-active");
} }
if (e.length > 0 && t.length > 0) for (let e = 0; e < t.length; e++) { if (e.length > 0 && t.length > 0)
let n = t[e], i = document.getElementById(n.getAttribute("aria-controls")); for (let e = 0; e < t.length; e++) {
i && (n.hasAttribute("data-video") && (null !== i.querySelector("iframe") ? i.querySelector("iframe").setAttribute("src", n.getAttribute("data-video")) : null !== i.querySelector("video") && i.querySelector("video").setAttribute("src", n.getAttribute("data-video"))), n.addEventListener("click", function (e) { let n = t[e],
i = document.getElementById(n.getAttribute("aria-controls"));
i &&
(n.hasAttribute("data-video") &&
(null !== i.querySelector("iframe")
? i
.querySelector("iframe")
.setAttribute("src", n.getAttribute("data-video"))
: null !== i.querySelector("video") &&
i
.querySelector("video")
.setAttribute("src", n.getAttribute("data-video"))),
n.addEventListener("click", function (e) {
var t; var t;
e.preventDefault(), n.hasAttribute("aria-controls") && (t = i) && (document.body.classList.add("modal-is-active"), t.classList.add("is-active")) e.preventDefault(),
})) n.hasAttribute("aria-controls") &&
(t = i) &&
(document.body.classList.add("modal-is-active"),
t.classList.add("is-active"));
}));
} }
document.addEventListener("click", function (e) { document.addEventListener("click", function (e) {
(e.target.classList.contains("modal") || e.target.classList.contains("modal-close-trigger")) && (e.preventDefault(), n()) (e.target.classList.contains("modal") ||
}), document.addEventListener("keydown", function (e) { e.target.classList.contains("modal-close-trigger")) &&
27 === (e || window.event).keyCode && n() (e.preventDefault(), n());
}) }),
}(), function () { document.addEventListener("keydown", function (e) {
27 === (e || window.event).keyCode && n();
});
})(),
(function () {
"use strict"; "use strict";
const e = document.getElementById("pricing-toggle"); const e = document.getElementById("pricing-toggle");
function t() { function t() {
const t = document.getElementsByClassName("pricing-switchable"); const t = document.getElementsByClassName("pricing-switchable");
if (e.checked) for (let e = 0; e < t.length; e++) t[e].innerHTML = t[e].getAttribute("data-pricing-yearly"); else for (let e = 0; e < t.length; e++) t[e].innerHTML = t[e].getAttribute("data-pricing-monthly") if (e.checked)
for (let e = 0; e < t.length; e++)
t[e].innerHTML = t[e].getAttribute("data-pricing-yearly");
else
for (let e = 0; e < t.length; e++)
t[e].innerHTML = t[e].getAttribute("data-pricing-monthly");
} }
e && (window.addEventListener("load", t), e.addEventListener("change", t)) e && (window.addEventListener("load", t), e.addEventListener("change", t));
}(), function () { })(),
(function () {
"use strict"; "use strict";
const e = document.querySelectorAll("[class*=reveal-]"); const e = document.querySelectorAll("[class*=reveal-]");
let t = window.innerHeight; let t = window.innerHeight;
@ -139,58 +252,89 @@
function n(e, t) { function n(e, t) {
var n = 0; var n = 0;
return function () { return function () {
var i = (new Date).getTime(); var i = new Date().getTime();
if (!(i - n < e)) return n = i, t.apply(void 0, arguments) if (!(i - n < e)) return (n = i), t.apply(void 0, arguments);
} };
} }
function i() { function i() {
for (let i = 0; i < e.length; i++) { for (let i = 0; i < e.length; i++) {
let s = e[i], a = s.getAttribute("data-reveal-delay"), let s = e[i],
l = s.getAttribute("data-reveal-offset") ? s.getAttribute("data-reveal-offset") : "200", a = s.getAttribute("data-reveal-delay"),
c = s.getAttribute("data-reveal-container") ? s.closest(s.getAttribute("data-reveal-container")) : s; l = s.getAttribute("data-reveal-offset")
n = l, c.getBoundingClientRect().top <= t - n && !s.classList.contains("is-revealed") && (a && 0 !== a ? setTimeout(function () { ? s.getAttribute("data-reveal-offset")
s.classList.add("is-revealed") : "200",
}, a) : s.classList.add("is-revealed")) c = s.getAttribute("data-reveal-container")
? s.closest(s.getAttribute("data-reveal-container"))
: s;
(n = l),
c.getBoundingClientRect().top <= t - n &&
!s.classList.contains("is-revealed") &&
(a && 0 !== a
? setTimeout(function () {
s.classList.add("is-revealed");
}, a)
: s.classList.add("is-revealed"));
} }
var n; var n;
!function () { !(function () {
if (e.length > document.querySelectorAll("[class*=reveal-].is-revealed").length) return; if (
window.removeEventListener("load", i), window.removeEventListener("scroll", s), window.removeEventListener("resize", a) e.length >
}() document.querySelectorAll("[class*=reveal-].is-revealed").length
)
return;
window.removeEventListener("load", i),
window.removeEventListener("scroll", s),
window.removeEventListener("resize", a);
})();
} }
function s() { function s() {
n(30, i()) n(30, i());
} }
function a() { function a() {
t = window.innerHeight, n(30, i()) (t = window.innerHeight), n(30, i());
} }
e.length > 0 && document.body.classList.contains("has-animations") && (window.addEventListener("load", i), window.addEventListener("scroll", s), window.addEventListener("resize", a)) e.length > 0 &&
}(), function () { document.body.classList.contains("has-animations") &&
(window.addEventListener("load", i),
window.addEventListener("scroll", s),
window.addEventListener("resize", a));
})(),
(function () {
"use strict"; "use strict";
const e = document.getElementsByClassName("smooth-scroll"), t = (e, n, i, s, a) => { const e = document.getElementsByClassName("smooth-scroll"),
t = (e, n, i, s, a) => {
const l = n - e; const l = n - e;
let c = l / i; let c = l / i;
const o = function (e) { const o = (function (e) {
return e < .5 ? 2 * e * e : (4 - 2 * e) * e - 1 return e < 0.5 ? 2 * e * e : (4 - 2 * e) * e - 1;
}(c = Math.min(c, 1)); })((c = Math.min(c, 1)));
window.scroll(0, a + s * o), l < i && window.requestAnimationFrame(n => { window.scroll(0, a + s * o),
const l = n || (new Date).getTime(); l < i &&
t(e, l, i, s, a) window.requestAnimationFrame((n) => {
}) const l = n || new Date().getTime();
t(e, l, i, s, a);
});
}; };
if (e.length > 0) for (let n = 0; n < e.length; n++) { if (e.length > 0)
for (let n = 0; n < e.length; n++) {
e[n].addEventListener("click", function (e) { e[n].addEventListener("click", function (e) {
e.preventDefault(); e.preventDefault();
const n = e.target.closest(".smooth-scroll"), i = n.href.split("#")[1], s = document.getElementById(i), const n = e.target.closest(".smooth-scroll"),
i = n.href.split("#")[1],
s = document.getElementById(i),
a = n.getAttribute("data-duration") || 1e3; a = n.getAttribute("data-duration") || 1e3;
s && window.requestAnimationFrame(e => { s &&
const n = e || (new Date).getTime(), i = n, l = window.pageYOffset, c = s.getBoundingClientRect().top; window.requestAnimationFrame((e) => {
t(i, n, a, c, l) const n = e || new Date().getTime(),
}) i = n,
}) l = window.pageYOffset,
c = s.getBoundingClientRect().top;
t(i, n, a, c, l);
});
});
} }
}(); })();

View File

@ -1,28 +1,34 @@
;(function () { (function () {
'use strict' "use strict";
const navToggle = document.getElementById('header-nav-toggle') const navToggle = document.getElementById("header-nav-toggle");
const mainNav = document.getElementById('header-nav') const mainNav = document.getElementById("header-nav");
if (navToggle) { if (navToggle) {
// Open menu // Open menu
navToggle.addEventListener('click', function () { navToggle.addEventListener("click", function () {
document.body.classList.toggle('off-nav-is-active') document.body.classList.toggle("off-nav-is-active");
mainNav.classList.toggle('is-active') mainNav.classList.toggle("is-active");
if (mainNav.style.maxHeight) { if (mainNav.style.maxHeight) {
mainNav.style.maxHeight = null mainNav.style.maxHeight = null;
} else { } else {
mainNav.style.maxHeight = mainNav.scrollHeight + 'px' mainNav.style.maxHeight = mainNav.scrollHeight + "px";
} }
this.getAttribute('aria-expanded') === 'true' ? this.setAttribute('aria-expanded', 'false') : this.setAttribute('aria-expanded', 'true') this.getAttribute("aria-expanded") === "true"
}) ? this.setAttribute("aria-expanded", "false")
: this.setAttribute("aria-expanded", "true");
});
// Close menu // Close menu
document.addEventListener('click', function (e) { document.addEventListener("click", function (e) {
if (e.target !== mainNav && e.target !== navToggle && !mainNav.contains(e.target)) { if (
document.body.classList.remove('off-nav-is-active') e.target !== mainNav &&
mainNav.classList.remove('is-active') e.target !== navToggle &&
mainNav.style.maxHeight = null !mainNav.contains(e.target)
navToggle.setAttribute('aria-expanded', 'false') ) {
document.body.classList.remove("off-nav-is-active");
mainNav.classList.remove("is-active");
mainNav.style.maxHeight = null;
navToggle.setAttribute("aria-expanded", "false");
} }
}) });
} }
}()) })();

View File

@ -1,56 +1,65 @@
;(function () { (function () {
'use strict' "use strict";
const modals = document.getElementsByClassName('modal') const modals = document.getElementsByClassName("modal");
const modalTriggers = document.getElementsByClassName('modal-trigger') const modalTriggers = document.getElementsByClassName("modal-trigger");
function openModal (el) { function openModal(el) {
if (el) { if (el) {
document.body.classList.add('modal-is-active') document.body.classList.add("modal-is-active");
el.classList.add('is-active') el.classList.add("is-active");
} }
} }
function closeModals () { function closeModals() {
document.body.classList.remove('modal-is-active') document.body.classList.remove("modal-is-active");
for (let i = 0; i < modals.length; i++) { for (let i = 0; i < modals.length; i++) {
modals[i].classList.remove('is-active') modals[i].classList.remove("is-active");
} }
} }
if (modals.length > 0 && modalTriggers.length > 0) { if (modals.length > 0 && modalTriggers.length > 0) {
for (let i = 0; i < modalTriggers.length; i++) { for (let i = 0; i < modalTriggers.length; i++) {
let modalTrigger = modalTriggers[i] let modalTrigger = modalTriggers[i];
let modal = document.getElementById(modalTrigger.getAttribute('aria-controls')) let modal = document.getElementById(
modalTrigger.getAttribute("aria-controls")
);
if (modal) { if (modal) {
// Modal video // Modal video
if (modalTrigger.hasAttribute('data-video')) { if (modalTrigger.hasAttribute("data-video")) {
if (modal.querySelector('iframe') !== null) { if (modal.querySelector("iframe") !== null) {
modal.querySelector('iframe').setAttribute('src', modalTrigger.getAttribute('data-video')) modal
} else if (modal.querySelector('video') !== null) { .querySelector("iframe")
modal.querySelector('video').setAttribute('src', modalTrigger.getAttribute('data-video')) .setAttribute("src", modalTrigger.getAttribute("data-video"));
} else if (modal.querySelector("video") !== null) {
modal
.querySelector("video")
.setAttribute("src", modalTrigger.getAttribute("data-video"));
} }
} }
modalTrigger.addEventListener('click', function (e) { modalTrigger.addEventListener("click", function (e) {
e.preventDefault() e.preventDefault();
if (modalTrigger.hasAttribute('aria-controls')) { if (modalTrigger.hasAttribute("aria-controls")) {
openModal(modal) openModal(modal);
} }
}) });
} }
} }
} }
document.addEventListener('click', function (e) { document.addEventListener("click", function (e) {
if (e.target.classList.contains('modal') || e.target.classList.contains('modal-close-trigger')) { if (
e.preventDefault() e.target.classList.contains("modal") ||
closeModals() e.target.classList.contains("modal-close-trigger")
) {
e.preventDefault();
closeModals();
} }
}) });
document.addEventListener('keydown', function (event) { document.addEventListener("keydown", function (event) {
var e = event || window.event var e = event || window.event;
if (e.keyCode === 27) { if (e.keyCode === 27) {
closeModals() closeModals();
} }
}) });
}()) })();

View File

@ -1,16 +1,124 @@
var adjectives = ["small", "big", "large", "smelly", "new", "happy", "shiny", "old", "clean", "nice", "bad", "cool", var adjectives = [
"hot", "cold", "warm", "hungry", "slow", "fast", "red", "white", "black", "blue", "green", "basic", "strong", "small",
"cute", "poor", "nice", "huge", "rare", "lucky", "weak", "tall", "short", "tiny", "great", "long", "single", "rich", "big",
"young", "dirty", "fresh", "brown", "dark", "crazy", "sad", "loud", "brave", "calm", "silly", "smart"]; "large",
"smelly",
"new",
"happy",
"shiny",
"old",
"clean",
"nice",
"bad",
"cool",
"hot",
"cold",
"warm",
"hungry",
"slow",
"fast",
"red",
"white",
"black",
"blue",
"green",
"basic",
"strong",
"cute",
"poor",
"nice",
"huge",
"rare",
"lucky",
"weak",
"tall",
"short",
"tiny",
"great",
"long",
"single",
"rich",
"young",
"dirty",
"fresh",
"brown",
"dark",
"crazy",
"sad",
"loud",
"brave",
"calm",
"silly",
"smart",
];
var nouns = ["dog", "bat", "wrench", "apple", "pear", "ghost", "cat", "wolf", "squid", "goat", "snail", "hat", var nouns = [
"sock", "plum", "bear", "snake", "turtle", "horse", "spoon", "fork", "spider", "tree", "chair", "table", "dog",
"couch", "towel", "panda", "bread", "grape", "cake", "brick", "rat", "mouse", "bird", "oven", "phone", "photo", "bat",
"frog", "bear", "camel", "sheep", "shark", "tiger", "zebra", "duck", "eagle", "fish", "kitten", "lobster", "monkey", "wrench",
"owl", "puppy", "pig", "rabbit", "fox", "whale", "beaver", "gorilla", "lizard", "parrot", "sloth", "swan"]; "apple",
"pear",
"ghost",
"cat",
"wolf",
"squid",
"goat",
"snail",
"hat",
"sock",
"plum",
"bear",
"snake",
"turtle",
"horse",
"spoon",
"fork",
"spider",
"tree",
"chair",
"table",
"couch",
"towel",
"panda",
"bread",
"grape",
"cake",
"brick",
"rat",
"mouse",
"bird",
"oven",
"phone",
"photo",
"frog",
"bear",
"camel",
"sheep",
"shark",
"tiger",
"zebra",
"duck",
"eagle",
"fish",
"kitten",
"lobster",
"monkey",
"owl",
"puppy",
"pig",
"rabbit",
"fox",
"whale",
"beaver",
"gorilla",
"lizard",
"parrot",
"sloth",
"swan",
];
var adjective = adjectives[Math.floor(Math.random() * adjectives.length)]; var adjective = adjectives[Math.floor(Math.random() * adjectives.length)];
var noun = nouns[Math.floor(Math.random() * nouns.length)]; var noun = nouns[Math.floor(Math.random() * nouns.length)];
noun = noun.charAt(0).toUpperCase() + noun.substring(1); noun = noun.charAt(0).toUpperCase() + noun.substring(1);
adjective = adjective.charAt(0).toUpperCase() + adjective.substring(1); adjective = adjective.charAt(0).toUpperCase() + adjective.substring(1);
document.getElementById('input-01').value = adjective + noun; document.getElementById("input-01").value = adjective + noun;

View File

@ -1,22 +1,26 @@
;(function () { (function () {
'use strict' "use strict";
const pricingToggle = document.getElementById('pricing-toggle') const pricingToggle = document.getElementById("pricing-toggle");
if (pricingToggle) { if (pricingToggle) {
window.addEventListener('load', pricingSwitch) window.addEventListener("load", pricingSwitch);
pricingToggle.addEventListener('change', pricingSwitch) pricingToggle.addEventListener("change", pricingSwitch);
} }
function pricingSwitch () { function pricingSwitch() {
const switchables = document.getElementsByClassName('pricing-switchable') const switchables = document.getElementsByClassName("pricing-switchable");
if (pricingToggle.checked) { if (pricingToggle.checked) {
for (let i = 0; i < switchables.length; i++) { for (let i = 0; i < switchables.length; i++) {
switchables[i].innerHTML = switchables[i].getAttribute('data-pricing-yearly') switchables[i].innerHTML = switchables[i].getAttribute(
"data-pricing-yearly"
);
} }
} else { } else {
for (let i = 0; i < switchables.length; i++) { for (let i = 0; i < switchables.length; i++) {
switchables[i].innerHTML = switchables[i].getAttribute('data-pricing-monthly') switchables[i].innerHTML = switchables[i].getAttribute(
"data-pricing-monthly"
);
} }
} }
} }
}()) })();

View File

@ -1,62 +1,76 @@
;(function () { (function () {
'use strict' "use strict";
const revealEl = document.querySelectorAll('[class*=reveal-]') const revealEl = document.querySelectorAll("[class*=reveal-]");
let viewportHeight = window.innerHeight let viewportHeight = window.innerHeight;
function throttle (delay, fn) { function throttle(delay, fn) {
var lastCall = 0 var lastCall = 0;
return function () { return function () {
var now = new Date().getTime() var now = new Date().getTime();
if (now - lastCall < delay) { if (now - lastCall < delay) {
return return;
}
lastCall = now
return fn.apply(void 0, arguments)
} }
lastCall = now;
return fn.apply(void 0, arguments);
};
} }
function elementIsVisible (el, offset) { function elementIsVisible(el, offset) {
return (el.getBoundingClientRect().top <= viewportHeight - offset) return el.getBoundingClientRect().top <= viewportHeight - offset;
} }
function revealElements () { function revealElements() {
for (let i = 0; i < revealEl.length; i++) { for (let i = 0; i < revealEl.length; i++) {
let el = revealEl[i] let el = revealEl[i];
let revealDelay = el.getAttribute('data-reveal-delay') let revealDelay = el.getAttribute("data-reveal-delay");
let revealOffset = (el.getAttribute('data-reveal-offset') ? el.getAttribute('data-reveal-offset') : '200') let revealOffset = el.getAttribute("data-reveal-offset")
let listenedEl = (el.getAttribute('data-reveal-container') ? el.closest(el.getAttribute('data-reveal-container')) : el) ? el.getAttribute("data-reveal-offset")
if (elementIsVisible(listenedEl, revealOffset) && !el.classList.contains('is-revealed')) { : "200";
let listenedEl = el.getAttribute("data-reveal-container")
? el.closest(el.getAttribute("data-reveal-container"))
: el;
if (
elementIsVisible(listenedEl, revealOffset) &&
!el.classList.contains("is-revealed")
) {
if (revealDelay && revealDelay !== 0) { if (revealDelay && revealDelay !== 0) {
setTimeout(function () { setTimeout(function () {
el.classList.add('is-revealed') el.classList.add("is-revealed");
}, revealDelay) }, revealDelay);
} else { } else {
el.classList.add('is-revealed') el.classList.add("is-revealed");
} }
} }
} }
revealDone() revealDone();
} }
function revealScroll () { function revealScroll() {
throttle(30, revealElements()) throttle(30, revealElements());
} }
function revealResize () { function revealResize() {
viewportHeight = window.innerHeight viewportHeight = window.innerHeight;
throttle(30, revealElements()) throttle(30, revealElements());
} }
function revealDone () { function revealDone() {
if (revealEl.length > document.querySelectorAll('[class*=reveal-].is-revealed').length) return if (
window.removeEventListener('load', revealElements) revealEl.length >
window.removeEventListener('scroll', revealScroll) document.querySelectorAll("[class*=reveal-].is-revealed").length
window.removeEventListener('resize', revealResize) )
return;
window.removeEventListener("load", revealElements);
window.removeEventListener("scroll", revealScroll);
window.removeEventListener("resize", revealResize);
} }
if (revealEl.length > 0 && document.body.classList.contains('has-animations')) { if (
window.addEventListener('load', revealElements) revealEl.length > 0 &&
window.addEventListener('scroll', revealScroll) document.body.classList.contains("has-animations")
window.addEventListener('resize', revealResize) ) {
window.addEventListener("load", revealElements);
window.addEventListener("scroll", revealScroll);
window.addEventListener("resize", revealResize);
} }
}()) })();

View File

@ -1,51 +1,69 @@
;(function () { (function () {
'use strict' "use strict";
const smoothScrollLinks = document.getElementsByClassName('smooth-scroll') const smoothScrollLinks = document.getElementsByClassName("smooth-scroll");
const easeInOutQuad = function (t) { const easeInOutQuad = function (t) {
return t < 0.5 ? 2 * t * t : -1 + (4 - 2 * t) * t return t < 0.5 ? 2 * t * t : -1 + (4 - 2 * t) * t;
} };
const scrollToEl = (startTime, currentTime, duration, scrollEndElemTop, startScrollOffset) => { const scrollToEl = (
const runtime = currentTime - startTime startTime,
let progress = runtime / duration currentTime,
duration,
scrollEndElemTop,
startScrollOffset
) => {
const runtime = currentTime - startTime;
let progress = runtime / duration;
progress = Math.min(progress, 1) progress = Math.min(progress, 1);
const ease = easeInOutQuad(progress) const ease = easeInOutQuad(progress);
window.scroll(0, startScrollOffset + (scrollEndElemTop * ease)) window.scroll(0, startScrollOffset + scrollEndElemTop * ease);
if (runtime < duration) { if (runtime < duration) {
window.requestAnimationFrame((timestamp) => { window.requestAnimationFrame((timestamp) => {
const currentTime = timestamp || new Date().getTime() const currentTime = timestamp || new Date().getTime();
scrollToEl(startTime, currentTime, duration, scrollEndElemTop, startScrollOffset) scrollToEl(
}) startTime,
} currentTime,
duration,
scrollEndElemTop,
startScrollOffset
);
});
} }
};
if (smoothScrollLinks.length > 0) { if (smoothScrollLinks.length > 0) {
for (let i = 0; i < smoothScrollLinks.length; i++) { for (let i = 0; i < smoothScrollLinks.length; i++) {
const smoothScrollLink = smoothScrollLinks[i] const smoothScrollLink = smoothScrollLinks[i];
smoothScrollLink.addEventListener('click', function (e) { smoothScrollLink.addEventListener("click", function (e) {
e.preventDefault() e.preventDefault();
const link = e.target.closest('.smooth-scroll') const link = e.target.closest(".smooth-scroll");
const targetId = link.href.split('#')[1] const targetId = link.href.split("#")[1];
const target = document.getElementById(targetId) const target = document.getElementById(targetId);
const duration = link.getAttribute('data-duration') || 1000 const duration = link.getAttribute("data-duration") || 1000;
if (!target) return if (!target) return;
window.requestAnimationFrame((timestamp) => { window.requestAnimationFrame((timestamp) => {
const stamp = timestamp || new Date().getTime() const stamp = timestamp || new Date().getTime();
const start = stamp const start = stamp;
const startScrollOffset = window.pageYOffset const startScrollOffset = window.pageYOffset;
const scrollEndElemTop = target.getBoundingClientRect().top const scrollEndElemTop = target.getBoundingClientRect().top;
scrollToEl(start, stamp, duration, scrollEndElemTop, startScrollOffset) scrollToEl(
}) start,
}) stamp,
duration,
scrollEndElemTop,
startScrollOffset
);
});
});
} }
} }
}()) })();

View File

@ -7,53 +7,53 @@
* https://github.com/polonel/Snackbar/blob/master/LICENSE * https://github.com/polonel/Snackbar/blob/master/LICENSE
*/ */
(function(root, factory) { (function (root, factory) {
'use strict'; "use strict";
if (typeof define === 'function' && define.amd) { if (typeof define === "function" && define.amd) {
define([], function() { define([], function () {
return (root.Snackbar = factory()); return (root.Snackbar = factory());
}); });
} else if (typeof module === 'object' && module.exports) { } else if (typeof module === "object" && module.exports) {
module.exports = root.Snackbar = factory(); module.exports = root.Snackbar = factory();
} else { } else {
root.Snackbar = factory(); root.Snackbar = factory();
} }
})(this, function() { })(this, function () {
var Snackbar = {}; var Snackbar = {};
Snackbar.current = null; Snackbar.current = null;
var $defaults = { var $defaults = {
text: 'Default Text', text: "Default Text",
textColor: '#FFFFFF', textColor: "#FFFFFF",
width: 'auto', width: "auto",
showAction: true, showAction: true,
actionText: 'Dismiss', actionText: "Dismiss",
actionTextAria: 'Dismiss, Description for Screen Readers', actionTextAria: "Dismiss, Description for Screen Readers",
alertScreenReader: false, alertScreenReader: false,
actionTextColor: '#4CAF50', actionTextColor: "#4CAF50",
showSecondButton: false, showSecondButton: false,
secondButtonText: '', secondButtonText: "",
secondButtonAria: 'Description for Screen Readers', secondButtonAria: "Description for Screen Readers",
secondButtonTextColor: '#4CAF50', secondButtonTextColor: "#4CAF50",
backgroundColor: '#323232', backgroundColor: "#323232",
pos: 'bottom-left', pos: "bottom-left",
duration: 5000, duration: 5000,
customClass: '', customClass: "",
onActionClick: function(element) { onActionClick: function (element) {
element.style.opacity = 0; element.style.opacity = 0;
}, },
onSecondButtonClick: function(element) {}, onSecondButtonClick: function (element) {},
onClose: function(element) {} onClose: function (element) {},
}; };
Snackbar.show = function($options) { Snackbar.show = function ($options) {
var options = Extend(true, $defaults, $options); var options = Extend(true, $defaults, $options);
if (Snackbar.current) { if (Snackbar.current) {
Snackbar.current.style.opacity = 0; Snackbar.current.style.opacity = 0;
setTimeout( setTimeout(
function() { function () {
var $parent = this.parentElement; var $parent = this.parentElement;
if ($parent) if ($parent)
// possible null if too many/fast Snackbars // possible null if too many/fast Snackbars
@ -63,39 +63,39 @@
); );
} }
Snackbar.snackbar = document.createElement('div'); Snackbar.snackbar = document.createElement("div");
Snackbar.snackbar.className = 'snackbar-container ' + options.customClass; Snackbar.snackbar.className = "snackbar-container " + options.customClass;
Snackbar.snackbar.style.width = options.width; Snackbar.snackbar.style.width = options.width;
var $p = document.createElement('p'); var $p = document.createElement("p");
$p.style.margin = 0; $p.style.margin = 0;
$p.style.padding = 0; $p.style.padding = 0;
$p.style.color = options.textColor; $p.style.color = options.textColor;
$p.style.fontSize = '14px'; $p.style.fontSize = "14px";
$p.style.fontWeight = 300; $p.style.fontWeight = 300;
$p.style.lineHeight = '1em'; $p.style.lineHeight = "1em";
$p.innerHTML = options.text; $p.innerHTML = options.text;
Snackbar.snackbar.appendChild($p); Snackbar.snackbar.appendChild($p);
Snackbar.snackbar.style.background = options.backgroundColor; Snackbar.snackbar.style.background = options.backgroundColor;
if (options.showSecondButton) { if (options.showSecondButton) {
var secondButton = document.createElement('button'); var secondButton = document.createElement("button");
secondButton.className = 'action'; secondButton.className = "action";
secondButton.innerHTML = options.secondButtonText; secondButton.innerHTML = options.secondButtonText;
secondButton.setAttribute('aria-label', options.secondButtonAria); secondButton.setAttribute("aria-label", options.secondButtonAria);
secondButton.style.color = options.secondButtonTextColor; secondButton.style.color = options.secondButtonTextColor;
secondButton.addEventListener('click', function() { secondButton.addEventListener("click", function () {
options.onSecondButtonClick(Snackbar.snackbar); options.onSecondButtonClick(Snackbar.snackbar);
}); });
Snackbar.snackbar.appendChild(secondButton); Snackbar.snackbar.appendChild(secondButton);
} }
if (options.showAction) { if (options.showAction) {
var actionButton = document.createElement('button'); var actionButton = document.createElement("button");
actionButton.className = 'action'; actionButton.className = "action";
actionButton.innerHTML = options.actionText; actionButton.innerHTML = options.actionText;
actionButton.setAttribute('aria-label', options.actionTextAria); actionButton.setAttribute("aria-label", options.actionTextAria);
actionButton.style.color = options.actionTextColor; actionButton.style.color = options.actionTextColor;
actionButton.addEventListener('click', function() { actionButton.addEventListener("click", function () {
options.onActionClick(Snackbar.snackbar); options.onActionClick(Snackbar.snackbar);
}); });
Snackbar.snackbar.appendChild(actionButton); Snackbar.snackbar.appendChild(actionButton);
@ -103,12 +103,12 @@
if (options.duration) { if (options.duration) {
setTimeout( setTimeout(
function() { function () {
if (Snackbar.current === this) { if (Snackbar.current === this) {
Snackbar.current.style.opacity = 0; Snackbar.current.style.opacity = 0;
// When natural remove event occurs let's move the snackbar to its origins // When natural remove event occurs let's move the snackbar to its origins
Snackbar.current.style.top = '-100px'; Snackbar.current.style.top = "-100px";
Snackbar.current.style.bottom = '-100px'; Snackbar.current.style.bottom = "-100px";
} }
}.bind(Snackbar.snackbar), }.bind(Snackbar.snackbar),
options.duration options.duration
@ -116,15 +116,14 @@
} }
if (options.alertScreenReader) { if (options.alertScreenReader) {
Snackbar.snackbar.setAttribute('role', 'alert'); Snackbar.snackbar.setAttribute("role", "alert");
} }
Snackbar.snackbar.addEventListener( Snackbar.snackbar.addEventListener(
'transitionend', "transitionend",
function(event, elapsed) { function (event, elapsed) {
if (event.propertyName === 'opacity' && this.style.opacity === '0') { if (event.propertyName === "opacity" && this.style.opacity === "0") {
if (typeof(options.onClose) === 'function') if (typeof options.onClose === "function") options.onClose(this);
options.onClose(this);
this.parentElement.removeChild(this); this.parentElement.removeChild(this);
if (Snackbar.current === this) { if (Snackbar.current === this) {
@ -141,10 +140,13 @@
var $top = getComputedStyle(Snackbar.snackbar).top; var $top = getComputedStyle(Snackbar.snackbar).top;
Snackbar.snackbar.style.opacity = 1; Snackbar.snackbar.style.opacity = 1;
Snackbar.snackbar.className = Snackbar.snackbar.className =
'snackbar-container ' + options.customClass + ' snackbar-pos ' + options.pos; "snackbar-container " +
options.customClass +
" snackbar-pos " +
options.pos;
}; };
Snackbar.close = function() { Snackbar.close = function () {
if (Snackbar.current) { if (Snackbar.current) {
Snackbar.current.style.opacity = 0; Snackbar.current.style.opacity = 0;
} }
@ -152,21 +154,24 @@
// Pure JS Extend // Pure JS Extend
// http://gomakethings.com/vanilla-javascript-version-of-jquery-extend/ // http://gomakethings.com/vanilla-javascript-version-of-jquery-extend/
var Extend = function() { var Extend = function () {
var extended = {}; var extended = {};
var deep = false; var deep = false;
var i = 0; var i = 0;
var length = arguments.length; var length = arguments.length;
if (Object.prototype.toString.call(arguments[0]) === '[object Boolean]') { if (Object.prototype.toString.call(arguments[0]) === "[object Boolean]") {
deep = arguments[0]; deep = arguments[0];
i++; i++;
} }
var merge = function(obj) { var merge = function (obj) {
for (var prop in obj) { for (var prop in obj) {
if (Object.prototype.hasOwnProperty.call(obj, prop)) { if (Object.prototype.hasOwnProperty.call(obj, prop)) {
if (deep && Object.prototype.toString.call(obj[prop]) === '[object Object]') { if (
deep &&
Object.prototype.toString.call(obj[prop]) === "[object Object]"
) {
extended[prop] = Extend(true, extended[prop], obj[prop]); extended[prop] = Extend(true, extended[prop], obj[prop]);
} else { } else {
extended[prop] = obj[prop]; extended[prop] = obj[prop];

View File

@ -1,20 +1,29 @@
<!DOCTYPE html> <!DOCTYPE html>
<html lang="en" class="no-js"> <html lang="en" class="no-js">
<head> <head>
<meta charset="utf-8"> <meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width,initial-scale=1"> <meta name="viewport" content="width=device-width,initial-scale=1" />
<title>Neon Chat</title> <title>Neon Chat</title>
<link rel="stylesheet" href="css/landing.css"> <link rel="stylesheet" href="css/landing.css" />
<link rel="shortcut icon" href="images/logo.svg"> <link rel="shortcut icon" href="images/logo.svg" />
<meta property="og:title" content="Neonchat - Decentralized video calls"> <meta property="og:title" content="Neonchat - Decentralized video calls" />
<meta property="og:description" content="Decentralized video <meta
property="og:description"
content="Decentralized video
calling provides real-time HD quality and latency simply calling provides real-time HD quality and latency simply
not available with traditional technology."> not available with traditional technology."
<meta property="og:image" content="https://neonchat.io/images/preview.png"> />
<meta property="og:url" content="https://neonchat.io/"> <meta
property="og:image"
content="https://neonchat.io/images/preview.png"
/>
<meta property="og:url" content="https://neonchat.io/" />
<!-- Global site tag (gtag.js) - Google Analytics --> <!-- Global site tag (gtag.js) - Google Analytics -->
<script async src="https://www.googletagmanager.com/gtag/js?id=UA-162048272-1"></script> <script
async
src="https://www.googletagmanager.com/gtag/js?id=UA-162048272-1"
></script>
<script> <script>
window.dataLayer = window.dataLayer || []; window.dataLayer = window.dataLayer || [];
@ -22,24 +31,33 @@
dataLayer.push(arguments); dataLayer.push(arguments);
} }
gtag('js', new Date()); gtag("js", new Date());
gtag('config', 'UA-162048272-1'); gtag("config", "UA-162048272-1");
</script> </script>
</head> </head>
<body class="has-animations"> <body class="has-animations">
<div class="body-wrap"> <div class="body-wrap">
<header class="site-header reveal-from-top"> <header class="site-header reveal-from-top">
<div class="container"> <div class="container">
<div class="site-header-inner"> <div class="site-header-inner">
<div class="brand"> <div class="brand">
<h1 class="m-0"><a href="/"><img src="images/logo.svg" alt="Neon" <h1 class="m-0">
width="32" <a href="/"
height="32"></a> ><img src="images/logo.svg" alt="Neon" width="32" height="32"
/></a>
</h1> </h1>
</div> </div>
<button id="header-nav-toggle" class="header-nav-toggle" aria-controls="primary-menu" <button
aria-expanded="false"><span class="screen-reader">Menu</span> <span class="hamburger"><span id="header-nav-toggle"
class="hamburger-inner"></span></span></button> class="header-nav-toggle"
aria-controls="primary-menu"
aria-expanded="false"
>
<span class="screen-reader">Menu</span>
<span class="hamburger"
><span class="hamburger-inner"></span
></span>
</button>
</div> </div>
</div> </div>
</header> </header>
@ -49,24 +67,46 @@
<div class="hero-inner section-inner"> <div class="hero-inner section-inner">
<div class="split-wrap invert-mobile"> <div class="split-wrap invert-mobile">
<div class="split-item"> <div class="split-item">
<div class="hero-content split-item-content center-content-mobile"><h1 <div
class="mt-0 mb-16 reveal-from-bottom" data-reveal-delay="150">Neon Chat.<br>The most class="hero-content split-item-content center-content-mobile"
advanced >
video chat ever created.</h1> <h1
<p class="mt-0 mb-32 reveal-from-bottom" data-reveal-delay="300">Decentralized video class="mt-0 mb-16 reveal-from-bottom"
calling provides quality and latency simply data-reveal-delay="150"
not available with traditional technology.</p> >
<div class="reveal-from-bottom" data-reveal-delay="450"><a Neon Chat.<br />The most advanced video chat ever created.
</h1>
<p
class="mt-0 mb-32 reveal-from-bottom"
data-reveal-delay="300"
>
Decentralized video calling provides quality and latency
simply not available with traditional technology.
</p>
<div class="reveal-from-bottom" data-reveal-delay="450">
<a
class="button button-primary button-wide-mobile pulse" class="button button-primary button-wide-mobile pulse"
style="border:0; background: linear-gradient(100deg, #376DF9 0, #FF5FA0 75%, #FFC55A 100%);" style="
href="/newroom">Try now</a> border: 0;
background: linear-gradient(
100deg,
#376df9 0,
#ff5fa0 75%,
#ffc55a 100%
);
"
href="/newroom"
>Try now</a
>
</div> </div>
</div> </div>
<style>@media (min-width: 641px) { <style>
@media (min-width: 641px) {
.hero .split-wrap .split-item { .hero .split-wrap .split-item {
min-height: 492px min-height: 492px;
} }
}</style> }
</style>
</div> </div>
</div> </div>
</div> </div>
@ -124,74 +164,126 @@
<div class="container"> <div class="container">
<div class="features-tiles-inner section-inner has-top-divider"> <div class="features-tiles-inner section-inner has-top-divider">
<div class="section-header"> <div class="section-header">
<div class="container-xs reveal-from-bottom" data-reveal-delay="650"><h2 class="mt-0 mb-16">See <div
the whole picture</h2> class="container-xs reveal-from-bottom"
<p class="m-0">Neon Chat is built radically different. We ditched slow bulky servers, data-reveal-delay="650"
opting for decentralized peer to peer calling. Maximum video quality and >
lowest latency. Its good, trust us.</p></div> <h2 class="mt-0 mb-16">See the whole picture</h2>
<p class="m-0">
Neon Chat is built radically different. We ditched slow
bulky servers, opting for decentralized peer to peer
calling. Maximum video quality and lowest latency. Its good,
trust us.
</p>
</div>
</div> </div>
<div class="tiles-wrap"> <div class="tiles-wrap">
<div class="tiles-item reveal-from-right"> <div class="tiles-item reveal-from-right">
<div class="tiles-item-inner"> <div class="tiles-item-inner">
<div class="features-tiles-item-header"> <div class="features-tiles-item-header">
<div class="features-tiles-item-image mb-16"><img <div class="features-tiles-item-image mb-16">
src="images/feature-tile-icon-01.svg" alt="Feature tile icon 01" width="72" <img
height="72"></div> src="images/feature-tile-icon-01.svg"
alt="Feature tile icon 01"
width="72"
height="72"
/>
</div> </div>
<div class="features-tiles-item-content"><h4 class="mt-0 mb-8">Lowest Latency</h4> </div>
<p class="m-0 text-sm">Breakthrough peer to peer WebRTC technology means your <div class="features-tiles-item-content">
video goes directly to the other person without a server. No middleman. No <h4 class="mt-0 mb-8">Lowest Latency</h4>
extra stops.</p> <p class="m-0 text-sm">
Breakthrough peer to peer WebRTC technology means your
video goes directly to the other person without a
server. No middleman. No extra stops.
</p>
</div> </div>
</div> </div>
</div> </div>
<div class="tiles-item reveal-from-left"> <div class="tiles-item reveal-from-left">
<div class="tiles-item-inner"> <div class="tiles-item-inner">
<div class="features-tiles-item-header"> <div class="features-tiles-item-header">
<div class="features-tiles-item-image mb-16"><img <div class="features-tiles-item-image mb-16">
src="images/feature-tile-icon-02.svg" alt="Feature tile icon 02" width="72" <img
height="72"></div> src="images/feature-tile-icon-02.svg"
alt="Feature tile icon 02"
width="72"
height="72"
/>
</div>
</div>
<div class="features-tiles-item-content">
<h4 class="mt-0 mb-8">Best Video Quality</h4>
<p class="m-0 text-sm">
State of the art VP9 video compression combined with our
custom scaling optimization means your calls have never
looked better.
</p>
</div> </div>
<div class="features-tiles-item-content"><h4 class="mt-0 mb-8">Best Video Quality</h4>
<p class="m-0 text-sm">State of the art VP9 video compression combined with our
custom scaling optimization means your calls have never looked better.</p></div>
</div> </div>
</div> </div>
<div class="tiles-item reveal-from-right"> <div class="tiles-item reveal-from-right">
<div class="tiles-item-inner"> <div class="tiles-item-inner">
<div class="features-tiles-item-header"> <div class="features-tiles-item-header">
<div class="features-tiles-item-image mb-16"><img <div class="features-tiles-item-image mb-16">
src="images/feature-tile-icon-03.svg" alt="Feature tile icon 03" width="72" <img
height="72"></div> src="images/feature-tile-icon-03.svg"
alt="Feature tile icon 03"
width="72"
height="72"
/>
</div>
</div>
<div class="features-tiles-item-content">
<h4 class="mt-0 mb-8">Total Privacy</h4>
<p class="m-0 text-sm">
Each chat room is single use, with data kept between you
and your friend. Your data is yours to keep.
</p>
</div> </div>
<div class="features-tiles-item-content"><h4 class="mt-0 mb-8">Total Privacy</h4>
<p class="m-0 text-sm">Each chat room is single use, with data
kept between you and your friend. Your data is yours to keep.</p></div>
</div> </div>
</div> </div>
<div class="tiles-item reveal-from-left"> <div class="tiles-item reveal-from-left">
<div class="tiles-item-inner"> <div class="tiles-item-inner">
<div class="features-tiles-item-header"> <div class="features-tiles-item-header">
<div class="features-tiles-item-image mb-16"><img <div class="features-tiles-item-image mb-16">
src="images/feature-tile-icon-04.svg" alt="Feature tile icon 04" width="72" <img
height="72"></div> src="images/feature-tile-icon-04.svg"
alt="Feature tile icon 04"
width="72"
height="72"
/>
</div>
</div>
<div class="features-tiles-item-content">
<h4 class="mt-0 mb-8">No Download Required</h4>
<p class="m-0 text-sm">
No download means you can get back to what matters most.
Just open Neon Chats in Chrome or Firefox.
</p>
</div> </div>
<div class="features-tiles-item-content"><h4 class="mt-0 mb-8">No Download Required</h4>
<p class="m-0 text-sm">No download means you can get back to what matters most. Just
open Neon Chats in Chrome or Firefox.</p></div>
</div> </div>
</div> </div>
<div class="tiles-item reveal-from-right"> <div class="tiles-item reveal-from-right">
<div class="tiles-item-inner"> <div class="tiles-item-inner">
<div class="features-tiles-item-header"> <div class="features-tiles-item-header">
<div class="features-tiles-item-image mb-16"><img <div class="features-tiles-item-image mb-16">
src="images/feature-tile-icon-05.svg" alt="Feature tile icon 05" width="72" <img
height="72"></div> src="images/feature-tile-icon-05.svg"
alt="Feature tile icon 05"
width="72"
height="72"
/>
</div> </div>
<div class="features-tiles-item-content"><h4 class="mt-0 mb-8">No Server Needed</h4> </div>
<p class="m-0 text-sm">Calls are entirely between you and your friend. <div class="features-tiles-item-content">
Decentralized from any server. Data never leaves the browser. Cool right?</p> <h4 class="mt-0 mb-8">No Server Needed</h4>
<p class="m-0 text-sm">
Calls are entirely between you and your friend.
Decentralized from any server. Data never leaves the
browser. Cool right?
</p>
</div> </div>
</div> </div>
</div> </div>
@ -199,32 +291,51 @@
<div class="tiles-item reveal-from-left"> <div class="tiles-item reveal-from-left">
<div class="tiles-item-inner"> <div class="tiles-item-inner">
<div class="features-tiles-item-header"> <div class="features-tiles-item-header">
<div class="features-tiles-item-image mb-16"><img <div class="features-tiles-item-image mb-16">
src="images/feature-tile-icon-06.svg" alt="Feature tile icon 06" width="72" <img
height="72"></div> src="images/feature-tile-icon-06.svg"
</div> alt="Feature tile icon 06"
<div class="features-tiles-item-content"><h4 class="mt-0 mb-8">Maximum Security</h4> width="72"
<p class="m-0 text-sm">End to end state of the art encryption means your calls are height="72"
exactly that. Your calls.</p></div> />
</div>
</div>
<div class="features-tiles-item-content">
<h4 class="mt-0 mb-8">Maximum Security</h4>
<p class="m-0 text-sm">
End to end state of the art encryption means your calls
are exactly that. Your calls.
</p>
</div>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
</section> </section>
<section class="section"> <section class="section">
<div class="container"> <div class="container">
<div class="section-inner has-top-divider"> <div class="section-inner has-top-divider">
<div class="container-xs"> <div class="container-xs">
<div class="section-header center-content"><h2 class="m-0">Tired of the old way of <div class="section-header center-content">
chatting? </h2></div> <h2 class="m-0">Tired of the old way of chatting?</h2>
</div>
<div class="center-content"> <div class="center-content">
<a class="button button-primary button-wide-mobile pulse" <a
style="border:0; background: linear-gradient(100deg, #376DF9 0, #FF5FA0 75%, #FFC55A 100%);" class="button button-primary button-wide-mobile pulse"
href="/newroom">Try now</a> style="
border: 0;
background: linear-gradient(
100deg,
#376df9 0,
#ff5fa0 75%,
#ffc55a 100%
);
"
href="/newroom"
>Try now</a
>
</div> </div>
</div> </div>
</div> </div>
@ -301,41 +412,58 @@
<!-- </div>--> <!-- </div>-->
<!-- </section>--> <!-- </section>-->
</div> </div>
</main> </main>
<footer class="site-footer center-content-mobile"> <footer class="site-footer center-content-mobile">
<div class="container"> <div class="container">
<div class="site-footer-inner"> <div class="site-footer-inner">
<div class="footer-top space-between text-xxs"> <div class="footer-top space-between text-xxs">
<div class="brand"> <div class="brand">
<a href="/"><img src="images/logo.svg" alt="Neon" width="32" height="32"></a> <a href="/"
><img src="images/logo.svg" alt="Neon" width="32" height="32"
/></a>
</div> </div>
<div class="footer-social"> <div class="footer-social">
<div><a href="https://github.com/ianramzy/decentralized-video-chat"> <div>
<svg width="16" height="16" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg"> <a
href="https://github.com/ianramzy/decentralized-video-chat"
>
<svg
width="16"
height="16"
viewBox="0 0 16 16"
xmlns="http://www.w3.org/2000/svg"
>
<title>GitHub</title> <title>GitHub</title>
<path d="M7.95 0C3.578 0 0 3.578 0 7.95c0 3.479 2.286 6.46 5.466 7.553.397.1.497-.199.497-.397v-1.392c-2.187.497-2.683-.994-2.683-.994-.398-.894-.895-1.192-.895-1.192-.696-.497.1-.497.1-.497.795.1 1.192.795 1.192.795.696 1.292 1.888.894 2.286.696.1-.497.298-.895.497-1.093-1.79-.2-3.578-.895-3.578-3.976 0-.894.298-1.59.795-2.087-.1-.198-.397-.993.1-2.086 0 0 .695-.2 2.186.795a6.408 6.408 0 0 1 1.987-.299c.696 0 1.392.1 1.988.299 1.49-.994 2.186-.795 2.186-.795.398 1.093.199 1.888.1 2.086.496.597.795 1.292.795 2.087 0 3.081-1.889 3.677-3.677 3.876.298.398.596.895.596 1.59v2.187c0 .198.1.496.596.397C13.714 14.41 16 11.43 16 7.95 15.9 3.578 12.323 0 7.95 0z"/> <path
d="M7.95 0C3.578 0 0 3.578 0 7.95c0 3.479 2.286 6.46 5.466 7.553.397.1.497-.199.497-.397v-1.392c-2.187.497-2.683-.994-2.683-.994-.398-.894-.895-1.192-.895-1.192-.696-.497.1-.497.1-.497.795.1 1.192.795 1.192.795.696 1.292 1.888.894 2.286.696.1-.497.298-.895.497-1.093-1.79-.2-3.578-.895-3.578-3.976 0-.894.298-1.59.795-2.087-.1-.198-.397-.993.1-2.086 0 0 .695-.2 2.186.795a6.408 6.408 0 0 1 1.987-.299c.696 0 1.392.1 1.988.299 1.49-.994 2.186-.795 2.186-.795.398 1.093.199 1.888.1 2.086.496.597.795 1.292.795 2.087 0 3.081-1.889 3.677-3.677 3.876.298.398.596.895.596 1.59v2.187c0 .198.1.496.596.397C13.714 14.41 16 11.43 16 7.95 15.9 3.578 12.323 0 7.95 0z"
/>
</svg> </svg>
</a></div> </a>
</ul>
</div> </div>
</div> </div>
<div class="footer-bottom space-between text-xxs invert-order-desktop"> </div>
<div
class="footer-bottom space-between text-xxs invert-order-desktop"
>
<nav class="footer-nav"> <nav class="footer-nav">
<ul class="list-reset"> <ul class="list-reset">
<li><a href="https://ianramzy.com">Made with ❤️ by Ian Ramzy</a></li> <li>
<!-- <li><a href="#">Contact</a></li>--> <a href="https://ianramzy.com">Made with ❤️ by Ian Ramzy</a>
</li>
<!-- <li><a href="#">Contact</a></li>-->
<!-- <li><a href="#">About us</a></li>--> <!-- <li><a href="#">About us</a></li>-->
<!-- <li><a href="#">FAQ's</a></li>--> <!-- <li><a href="#">FAQ's</a></li>-->
<!-- <li><a href="#">Support</a></li>--> <!-- <li><a href="#">Support</a></li>-->
</ul> </ul>
</nav> </nav>
<div class="footer-copyright">&copy; 2020 Neon Chat, all rights reserved</div> <div class="footer-copyright">
&copy; 2020 Neon Chat, all rights reserved
</div>
</div> </div>
</div> </div>
</div> </div>
</footer> </footer>
</div> </div>
<script src="js/landing.js"></script> <script src="js/landing.js"></script>
</body> </body>
</html> </html>

View File

@ -1,20 +1,29 @@
<!DOCTYPE html> <!DOCTYPE html>
<html lang="en" class="no-js"> <html lang="en" class="no-js">
<head> <head>
<meta charset="utf-8"> <meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width,initial-scale=1"> <meta name="viewport" content="width=device-width,initial-scale=1" />
<title>Neon Chat</title> <title>Neon Chat</title>
<link rel="stylesheet" href="css/landing.css"> <link rel="stylesheet" href="css/landing.css" />
<link rel="shortcut icon" href="images/logo.svg"> <link rel="shortcut icon" href="images/logo.svg" />
<meta property="og:title" content="Neonchat - Decentralized video calls"> <meta property="og:title" content="Neonchat - Decentralized video calls" />
<meta property="og:description" content="Decentralized video <meta
property="og:description"
content="Decentralized video
calling provides real-time HD quality and latency simply calling provides real-time HD quality and latency simply
not available with traditional technology."> not available with traditional technology."
<meta property="og:image" content="https://neonchat.io/images/preview.png"> />
<meta property="og:url" content="https://neonchat.io/"> <meta
property="og:image"
content="https://neonchat.io/images/preview.png"
/>
<meta property="og:url" content="https://neonchat.io/" />
<!-- Global site tag (gtag.js) - Google Analytics --> <!-- Global site tag (gtag.js) - Google Analytics -->
<script async src="https://www.googletagmanager.com/gtag/js?id=UA-162048272-1"></script> <script
async
src="https://www.googletagmanager.com/gtag/js?id=UA-162048272-1"
></script>
<script> <script>
window.dataLayer = window.dataLayer || []; window.dataLayer = window.dataLayer || [];
@ -22,44 +31,68 @@
dataLayer.push(arguments); dataLayer.push(arguments);
} }
gtag('js', new Date()); gtag("js", new Date());
gtag('config', 'UA-162048272-1'); gtag("config", "UA-162048272-1");
</script> </script>
</head> </head>
<body class="has-animations"> <body class="has-animations">
<div class="body-wrap"> <div class="body-wrap">
<header class="site-header reveal-from-top"> <header class="site-header reveal-from-top">
<div class="container"> <div class="container">
<div class="site-header-inner"> <div class="site-header-inner">
<div class="brand"><h1 class="m-0"><a href="/"><img src="images/logo.svg" alt="Neon" <div class="brand">
width="32" <h1 class="m-0">
height="32"></a></h1></div> <a href="/"
<button id="header-nav-toggle" class="header-nav-toggle" aria-controls="primary-menu" ><img src="images/logo.svg" alt="Neon" width="32" height="32"
aria-expanded="false"><span class="screen-reader">Menu</span> <span class="hamburger"><span /></a>
class="hamburger-inner"></span></span></button> </h1>
</div>
<button
id="header-nav-toggle"
class="header-nav-toggle"
aria-controls="primary-menu"
aria-expanded="false"
>
<span class="screen-reader">Menu</span>
<span class="hamburger"
><span class="hamburger-inner"></span
></span>
</button>
</div> </div>
</div> </div>
</header> </header>
<main class="site-content"> <main class="site-content">
<section class="hero section illustration-section-01"> <section class="hero section illustration-section-01">
<div class="container"> <div class="container">
<div class="hero-inner section-inner"> <div class="hero-inner section-inner">
<div class="split-wrap invert-mobile"> <div class="split-wrap invert-mobile">
<div class="split-item"> <div class="split-item">
<div class="hero-content split-item-content center-content-mobile"> <div
<h1 class="mt-0 mb-16 reveal-from-bottom" data-reveal-delay="150"> class="hero-content split-item-content center-content-mobile"
Get room. <br> Share URL. <br> Start chatting.</h1> >
<p class="mt-0 mb-32 reveal-from-bottom" data-reveal-delay="300"> <h1
Each chat has its own disposable URL. Just get a room and share your custom link. class="mt-0 mb-16 reveal-from-bottom"
It's really that easy. data-reveal-delay="150"
>
Get room. <br />
Share URL. <br />
Start chatting.
</h1>
<p
class="mt-0 mb-32 reveal-from-bottom"
data-reveal-delay="300"
>
Each chat has its own disposable URL. Just get a room and
share your custom link. It's really that easy.
</p> </p>
</div> </div>
<style>@media (min-width: 641px) { <style>
@media (min-width: 641px) {
.hero .split-wrap .split-item { .hero .split-wrap .split-item {
min-height: 492px min-height: 492px;
} }
}</style> }
</style>
</div> </div>
</div> </div>
</div> </div>
@ -69,14 +102,28 @@
<section class="cta section center-content-mobile reveal-from-bottom"> <section class="cta section center-content-mobile reveal-from-bottom">
<div class="container"> <div class="container">
<div class="cta-inner section-inner cta-split"> <div class="cta-inner section-inner cta-split">
<div class="cta-slogan"><h3 class="m-0">Pick a room name.<br> How about this one?</h3></div> <div class="cta-slogan">
<h3 class="m-0">
Pick a room name.<br />
How about this one?
</h3>
</div>
<div class="cta-action"> <div class="cta-action">
<div class="mb-24" style="margin-top: 30px"> <div class="mb-24" style="margin-top: 30px;">
<label class="form-label screen-reader" for="input-01">This is a label</label> <label class="form-label screen-reader" for="input-01"
>This is a label</label
>
<div class="form-group-desktop"> <div class="form-group-desktop">
<input class="form-input" type="text" id="input-01" value="PurpleSquid"> <input
<button class="button button-primary pulse" class="form-input"
onclick="{window.location.href = '/room/' + document.getElementById('input-01').value}"> type="text"
id="input-01"
value="PurpleSquid"
/>
<button
class="button button-primary pulse"
onclick="{window.location.href = '/room/' + document.getElementById('input-01').value}"
>
Go To My Room Go To My Room
</button> </button>
</div> </div>
@ -85,40 +132,55 @@
</div> </div>
</div> </div>
</section> </section>
</main> </main>
<footer class="site-footer center-content-mobile"> <footer class="site-footer center-content-mobile">
<div class="container"> <div class="container">
<div class="site-footer-inner"> <div class="site-footer-inner">
<div class="footer-top space-between text-xxs"> <div class="footer-top space-between text-xxs">
<div class="brand"> <div class="brand">
<a href="/"><img src="images/logo.svg" alt="Neon" width="32" height="32"></a> <a href="/"
><img src="images/logo.svg" alt="Neon" width="32" height="32"
/></a>
</div> </div>
<div class="footer-social"> <div class="footer-social">
<div><a href="https://github.com/ianramzy/decentralized-video-chat"> <div>
<svg width="16" height="16" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg"> <a
href="https://github.com/ianramzy/decentralized-video-chat"
>
<svg
width="16"
height="16"
viewBox="0 0 16 16"
xmlns="http://www.w3.org/2000/svg"
>
<title>GitHub</title> <title>GitHub</title>
<path d="M7.95 0C3.578 0 0 3.578 0 7.95c0 3.479 2.286 6.46 5.466 7.553.397.1.497-.199.497-.397v-1.392c-2.187.497-2.683-.994-2.683-.994-.398-.894-.895-1.192-.895-1.192-.696-.497.1-.497.1-.497.795.1 1.192.795 1.192.795.696 1.292 1.888.894 2.286.696.1-.497.298-.895.497-1.093-1.79-.2-3.578-.895-3.578-3.976 0-.894.298-1.59.795-2.087-.1-.198-.397-.993.1-2.086 0 0 .695-.2 2.186.795a6.408 6.408 0 0 1 1.987-.299c.696 0 1.392.1 1.988.299 1.49-.994 2.186-.795 2.186-.795.398 1.093.199 1.888.1 2.086.496.597.795 1.292.795 2.087 0 3.081-1.889 3.677-3.677 3.876.298.398.596.895.596 1.59v2.187c0 .198.1.496.596.397C13.714 14.41 16 11.43 16 7.95 15.9 3.578 12.323 0 7.95 0z"/> <path
d="M7.95 0C3.578 0 0 3.578 0 7.95c0 3.479 2.286 6.46 5.466 7.553.397.1.497-.199.497-.397v-1.392c-2.187.497-2.683-.994-2.683-.994-.398-.894-.895-1.192-.895-1.192-.696-.497.1-.497.1-.497.795.1 1.192.795 1.192.795.696 1.292 1.888.894 2.286.696.1-.497.298-.895.497-1.093-1.79-.2-3.578-.895-3.578-3.976 0-.894.298-1.59.795-2.087-.1-.198-.397-.993.1-2.086 0 0 .695-.2 2.186.795a6.408 6.408 0 0 1 1.987-.299c.696 0 1.392.1 1.988.299 1.49-.994 2.186-.795 2.186-.795.398 1.093.199 1.888.1 2.086.496.597.795 1.292.795 2.087 0 3.081-1.889 3.677-3.677 3.876.298.398.596.895.596 1.59v2.187c0 .198.1.496.596.397C13.714 14.41 16 11.43 16 7.95 15.9 3.578 12.323 0 7.95 0z"
/>
</svg> </svg>
</a></div> </a>
</ul>
</div> </div>
</div> </div>
</div> </div>
<div class="footer-bottom space-between text-xxs invert-order-desktop"> </div>
<div
class="footer-bottom space-between text-xxs invert-order-desktop"
>
<nav class="footer-nav"> <nav class="footer-nav">
<ul class="list-reset"> <ul class="list-reset">
<li><a href="https://ianramzy.com">Made with ❤️ by Ian Ramzy</a></li> <li>
<a href="https://ianramzy.com">Made with ❤️ by Ian Ramzy</a>
</li>
</ul> </ul>
</nav> </nav>
<div class="footer-copyright">&copy; 2020 Neon Chat, all rights reserved</div> <div class="footer-copyright">
&copy; 2020 Neon Chat, all rights reserved
</div> </div>
</div> </div>
</div> </div>
</footer> </footer>
</div> </div>
<script src="js/landing.js"></script> <script src="js/landing.js"></script>
<script src="js/newroom.js"></script> <script src="js/newroom.js"></script>
</body> </body>
</html> </html>

View File

@ -1,114 +1,111 @@
require('dotenv').config(); require("dotenv").config();
var sslRedirect = require('heroku-ssl-redirect'); var sslRedirect = require("heroku-ssl-redirect");
var twilio = require('twilio')(process.env.TWILIO_ACCOUNT_SID, process.env.TWILIO_AUTH_TOKEN); var twilio = require("twilio")(
var express = require('express'); process.env.TWILIO_ACCOUNT_SID,
process.env.TWILIO_AUTH_TOKEN
);
var express = require("express");
var app = express(); var app = express();
var http = require('http').createServer(app); var http = require("http").createServer(app);
var io = require('socket.io')(http); var io = require("socket.io")(http);
var path = require('path'); var path = require("path");
var public = path.join(__dirname, 'public'); var public = path.join(__dirname, "public");
// enable ssl redirect // enable ssl redirect
app.use(sslRedirect()); app.use(sslRedirect());
app.get("/", function (req, res) {
app.get('/', function (req, res) { res.sendFile(path.join(public, "landing.html"));
res.sendFile(path.join(public, 'landing.html'));
}); });
app.get('/newroom', function (req, res) { app.get("/newroom", function (req, res) {
res.sendFile(path.join(public, 'newroom.html')); res.sendFile(path.join(public, "newroom.html"));
}); });
app.get('/room/*', function (req, res) { app.get("/room/*", function (req, res) {
res.sendFile(path.join(public, 'chat.html')); res.sendFile(path.join(public, "chat.html"));
}); });
app.use(express.static('public')); app.use(express.static("public"));
function logIt(msg, room) { function logIt(msg, room) {
console.log(room + ": " + msg) console.log(room + ": " + msg);
} }
// When a socket connects, set up the specific listeners we will use. // When a socket connects, set up the specific listeners we will use.
io.on('connection', function (socket) { io.on("connection", function (socket) {
// When a client tries to join a room, only allow them if they are first or // When a client tries to join a room, only allow them if they are first or
// second in the room. Otherwise it is full. // second in the room. Otherwise it is full.
socket.on('join', function (room) { socket.on("join", function (room) {
logIt('A client joined the room', room); logIt("A client joined the room", room);
var clients = io.sockets.adapter.rooms[room]; var clients = io.sockets.adapter.rooms[room];
var numClients = typeof clients !== 'undefined' ? clients.length : 0; var numClients = typeof clients !== "undefined" ? clients.length : 0;
if (numClients === 0) { if (numClients === 0) {
socket.join(room); socket.join(room);
} else if (numClients === 1) { } else if (numClients === 1) {
socket.join(room); socket.join(room);
// When the client is second to join the room, both clients are ready. // When the client is second to join the room, both clients are ready.
logIt('Broadcasting ready message', room); logIt("Broadcasting ready message", room);
socket.broadcast.to(room).emit('willInitiateCall', room); socket.broadcast.to(room).emit("willInitiateCall", room);
socket.emit('ready', room).to(room); socket.emit("ready", room).to(room);
socket.broadcast.to(room).emit('ready', room); socket.broadcast.to(room).emit("ready", room);
} else { } else {
logIt("room already full", room); logIt("room already full", room);
socket.emit('full', room); socket.emit("full", room);
} }
}); });
// When receiving the token message, use the Twilio REST API to request an // When receiving the token message, use the Twilio REST API to request an
// token to get ephemeral credentials to use the TURN server. // token to get ephemeral credentials to use the TURN server.
socket.on('token', function (room) { socket.on("token", function (room) {
logIt('Received token request', room); logIt("Received token request", room);
twilio.tokens.create(function (err, response) { twilio.tokens.create(function (err, response) {
if (err) { if (err) {
logIt(err, room); logIt(err, room);
} else { } else {
logIt('Token generated. Returning it to the browser client', room); logIt("Token generated. Returning it to the browser client", room);
socket.emit('token', response).to(room); socket.emit("token", response).to(room);
} }
}); });
}); });
// Relay candidate messages // Relay candidate messages
socket.on('candidate', function (candidate, room) { socket.on("candidate", function (candidate, room) {
logIt('Received candidate. Broadcasting...', room); logIt("Received candidate. Broadcasting...", room);
socket.broadcast.to(room).emit('candidate', candidate); socket.broadcast.to(room).emit("candidate", candidate);
}); });
// Relay offers // Relay offers
socket.on('offer', function (offer, room) { socket.on("offer", function (offer, room) {
logIt('Received offer. Broadcasting...', room); logIt("Received offer. Broadcasting...", room);
socket.broadcast.to(room).emit('offer', offer); socket.broadcast.to(room).emit("offer", offer);
}); });
// Relay answers // Relay answers
socket.on('answer', function (answer, room) { socket.on("answer", function (answer, room) {
logIt('Received answer. Broadcasting...', room); logIt("Received answer. Broadcasting...", room);
socket.broadcast.to(room).emit('answer', answer); socket.broadcast.to(room).emit("answer", answer);
}); });
// Relay answers // Relay answers
socket.on('sendCaptions', function (captions, room) { socket.on("sendCaptions", function (captions, room) {
// logIt(captions, room); // logIt(captions, room);
socket.broadcast.to(room).emit('recieveCaptions', captions); socket.broadcast.to(room).emit("recieveCaptions", captions);
}); });
// Relay answers // Relay answers
socket.on('requestToggleCaptions', function (room) { socket.on("requestToggleCaptions", function (room) {
logIt("requesting captions", room); logIt("requesting captions", room);
socket.broadcast.to(room).emit('requestToggleCaptions'); socket.broadcast.to(room).emit("requestToggleCaptions");
}); });
// Relay chat messages // Relay chat messages
socket.on('chat message', function(msg, room){ socket.on("chat message", function (msg, room) {
socket.broadcast.to(room).emit('chat message', msg); socket.broadcast.to(room).emit("chat message", msg);
}); });
}); });
var port = process.env.PORT || 3000; var port = process.env.PORT || 3000;
http.listen(port, function () { http.listen(port, function () {
console.log("http://localhost:" + port); console.log("http://localhost:" + port);
}); });