mirror of
https://github.com/ianramzy/decentralized-video-chat.git
synced 2024-11-23 18:49:21 +08:00
Run prettier
This commit is contained in:
parent
d131909b8e
commit
f9b94795e7
@ -3,18 +3,30 @@
|
|||||||
<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,36 +34,31 @@
|
|||||||
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-item customer">-->
|
||||||
<!-- <div class="message-bloc">-->
|
<!-- <div class="message-bloc">-->
|
||||||
<!-- <div class="message">Have you tried this chat?</div>-->
|
<!-- <div class="message">Have you tried this chat?</div>-->
|
||||||
@ -63,12 +70,10 @@
|
|||||||
<!-- <div class="message">Not yet! It looks awesome</div>-->
|
<!-- <div class="message">Not yet! It looks awesome</div>-->
|
||||||
<!-- </div>-->
|
<!-- </div>-->
|
||||||
<!-- </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()}">
|
||||||
@ -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,14 +121,17 @@
|
|||||||
<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>
|
||||||
|
@ -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
@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}())
|
})();
|
||||||
|
@ -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
|
||||||
@ -11,161 +11,185 @@
|
|||||||
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);
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}())
|
})();
|
||||||
|
@ -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"
|
||||||
|
);
|
||||||
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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);
|
||||||
|
});
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}();
|
})();
|
||||||
|
@ -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");
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
}())
|
})();
|
||||||
|
@ -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();
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
}())
|
})();
|
||||||
|
@ -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;
|
||||||
|
@ -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"
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}())
|
})();
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
}())
|
})();
|
||||||
|
@ -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
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}())
|
})();
|
||||||
|
@ -8,13 +8,13 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
(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();
|
||||||
@ -24,27 +24,27 @@
|
|||||||
|
|
||||||
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) {
|
||||||
@ -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);
|
||||||
@ -107,8 +107,8 @@
|
|||||||
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,7 +140,10 @@
|
|||||||
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 () {
|
||||||
@ -158,7 +160,7 @@
|
|||||||
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++;
|
||||||
}
|
}
|
||||||
@ -166,7 +168,10 @@
|
|||||||
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];
|
||||||
|
@ -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,8 +31,8 @@
|
|||||||
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">
|
||||||
@ -32,14 +41,23 @@
|
|||||||
<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,36 +412,53 @@
|
|||||||
<!-- </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>
|
||||||
|
<a href="https://ianramzy.com">Made with ❤️ by Ian Ramzy</a>
|
||||||
|
</li>
|
||||||
<!-- <li><a href="#">Contact</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">© 2020 Neon Chat, all rights reserved</div>
|
<div class="footer-copyright">
|
||||||
|
© 2020 Neon Chat, all rights reserved
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -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,8 +31,8 @@
|
|||||||
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">
|
||||||
@ -31,35 +40,59 @@
|
|||||||
<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,34 +132,49 @@
|
|||||||
</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">© 2020 Neon Chat, all rights reserved</div>
|
<div class="footer-copyright">
|
||||||
|
© 2020 Neon Chat, all rights reserved
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
97
server.js
97
server.js
@ -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);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user