Zipcall acquired.

remove .gitattributes


zipcall acquired
This commit is contained in:
Ian Ramzy 2020-11-20 20:54:28 -05:00
parent 4b92b8a538
commit b2f7c84290
60 changed files with 6 additions and 10286 deletions

View File

@ -1,6 +0,0 @@
# Required for all uses
# It takes 2 mins to get a free twilio account https://www.twilio.com/login
# Fill in your credentials below and rename this file to .env
TWILIO_ACCOUNT_SID=YourAccountSIDHere
LOCAL_AUTH_TOKEN=YourAuthTokenHere

2
.gitattributes vendored
View File

@ -1,2 +0,0 @@
* linguist-vendored
*.js linguist-vendored=false

4
.gitignore vendored
View File

@ -1,4 +0,0 @@
node_modules/
.DS_Store
/.idea
.env

87
LICENSE
View File

@ -1,87 +0,0 @@
Creative Commons Attribution-NonCommercial 4.0 International Public License
By exercising the Licensed Rights (defined below), You accept and agree to be bound by the terms and conditions of this Creative Commons Attribution-NonCommercial 4.0 International Public License ("Public License"). To the extent this Public License may be interpreted as a contract, You are granted the Licensed Rights in consideration of Your acceptance of these terms and conditions, and the Licensor grants You such rights in consideration of benefits the Licensor receives from making the Licensed Material available under these terms and conditions.
Section 1 Definitions.
Adapted Material means material subject to Copyright and Similar Rights that is derived from or based upon the Licensed Material and in which the Licensed Material is translated, altered, arranged, transformed, or otherwise modified in a manner requiring permission under the Copyright and Similar Rights held by the Licensor. For purposes of this Public License, where the Licensed Material is a musical work, performance, or sound recording, Adapted Material is always produced where the Licensed Material is synched in timed relation with a moving image.
Adapter's License means the license You apply to Your Copyright and Similar Rights in Your contributions to Adapted Material in accordance with the terms and conditions of this Public License.
Copyright and Similar Rights means copyright and/or similar rights closely related to copyright including, without limitation, performance, broadcast, sound recording, and Sui Generis Database Rights, without regard to how the rights are labeled or categorized. For purposes of this Public License, the rights specified in Section 2(b)(1)-(2) are not Copyright and Similar Rights.
Effective Technological Measures means those measures that, in the absence of proper authority, may not be circumvented under laws fulfilling obligations under Article 11 of the WIPO Copyright Treaty adopted on December 20, 1996, and/or similar international agreements.
Exceptions and Limitations means fair use, fair dealing, and/or any other exception or limitation to Copyright and Similar Rights that applies to Your use of the Licensed Material.
Licensed Material means the artistic or literary work, database, or other material to which the Licensor applied this Public License.
Licensed Rights means the rights granted to You subject to the terms and conditions of this Public License, which are limited to all Copyright and Similar Rights that apply to Your use of the Licensed Material and that the Licensor has authority to license.
Licensor means the individual(s) or entity(ies) granting rights under this Public License.
NonCommercial means not primarily intended for or directed towards commercial advantage or monetary compensation. For purposes of this Public License, the exchange of the Licensed Material for other material subject to Copyright and Similar Rights by digital file-sharing or similar means is NonCommercial provided there is no payment of monetary compensation in connection with the exchange.
Share means to provide material to the public by any means or process that requires permission under the Licensed Rights, such as reproduction, public display, public performance, distribution, dissemination, communication, or importation, and to make material available to the public including in ways that members of the public may access the material from a place and at a time individually chosen by them.
Sui Generis Database Rights means rights other than copyright resulting from Directive 96/9/EC of the European Parliament and of the Council of 11 March 1996 on the legal protection of databases, as amended and/or succeeded, as well as other essentially equivalent rights anywhere in the world.
You means the individual or entity exercising the Licensed Rights under this Public License. Your has a corresponding meaning.
Section 2 Scope.
License grant.
Subject to the terms and conditions of this Public License, the Licensor hereby grants You a worldwide, royalty-free, non-sublicensable, non-exclusive, irrevocable license to exercise the Licensed Rights in the Licensed Material to:
reproduce and Share the Licensed Material, in whole or in part, for NonCommercial purposes only; and
produce, reproduce, and Share Adapted Material for NonCommercial purposes only.
Exceptions and Limitations. For the avoidance of doubt, where Exceptions and Limitations apply to Your use, this Public License does not apply, and You do not need to comply with its terms and conditions.
Term. The term of this Public License is specified in Section 6(a).
Media and formats; technical modifications allowed. The Licensor authorizes You to exercise the Licensed Rights in all media and formats whether now known or hereafter created, and to make technical modifications necessary to do so. The Licensor waives and/or agrees not to assert any right or authority to forbid You from making technical modifications necessary to exercise the Licensed Rights, including technical modifications necessary to circumvent Effective Technological Measures. For purposes of this Public License, simply making modifications authorized by this Section 2(a)(4) never produces Adapted Material.
Downstream recipients.
Offer from the Licensor Licensed Material. Every recipient of the Licensed Material automatically receives an offer from the Licensor to exercise the Licensed Rights under the terms and conditions of this Public License.
No downstream restrictions. You may not offer or impose any additional or different terms or conditions on, or apply any Effective Technological Measures to, the Licensed Material if doing so restricts exercise of the Licensed Rights by any recipient of the Licensed Material.
No endorsement. Nothing in this Public License constitutes or may be construed as permission to assert or imply that You are, or that Your use of the Licensed Material is, connected with, or sponsored, endorsed, or granted official status by, the Licensor or others designated to receive attribution as provided in Section 3(a)(1)(A)(i).
Other rights.
Moral rights, such as the right of integrity, are not licensed under this Public License, nor are publicity, privacy, and/or other similar personality rights; however, to the extent possible, the Licensor waives and/or agrees not to assert any such rights held by the Licensor to the limited extent necessary to allow You to exercise the Licensed Rights, but not otherwise.
Patent and trademark rights are not licensed under this Public License.
To the extent possible, the Licensor waives any right to collect royalties from You for the exercise of the Licensed Rights, whether directly or through a collecting society under any voluntary or waivable statutory or compulsory licensing scheme. In all other cases the Licensor expressly reserves any right to collect such royalties, including when the Licensed Material is used other than for NonCommercial purposes.
Section 3 License Conditions.
Your exercise of the Licensed Rights is expressly made subject to the following conditions.
Attribution.
If You Share the Licensed Material (including in modified form), You must:
retain the following if it is supplied by the Licensor with the Licensed Material:
identification of the creator(s) of the Licensed Material and any others designated to receive attribution, in any reasonable manner requested by the Licensor (including by pseudonym if designated);
a copyright notice;
a notice that refers to this Public License;
a notice that refers to the disclaimer of warranties;
a URI or hyperlink to the Licensed Material to the extent reasonably practicable;
indicate if You modified the Licensed Material and retain an indication of any previous modifications; and
indicate the Licensed Material is licensed under this Public License, and include the text of, or the URI or hyperlink to, this Public License.
You may satisfy the conditions in Section 3(a)(1) in any reasonable manner based on the medium, means, and context in which You Share the Licensed Material. For example, it may be reasonable to satisfy the conditions by providing a URI or hyperlink to a resource that includes the required information.
If requested by the Licensor, You must remove any of the information required by Section 3(a)(1)(A) to the extent reasonably practicable.
If You Share Adapted Material You produce, the Adapter's License You apply must not prevent recipients of the Adapted Material from complying with this Public License.
Section 4 Sui Generis Database Rights.
Where the Licensed Rights include Sui Generis Database Rights that apply to Your use of the Licensed Material:
for the avoidance of doubt, Section 2(a)(1) grants You the right to extract, reuse, reproduce, and Share all or a substantial portion of the contents of the database for NonCommercial purposes only;
if You include all or a substantial portion of the database contents in a database in which You have Sui Generis Database Rights, then the database in which You have Sui Generis Database Rights (but not its individual contents) is Adapted Material; and
You must comply with the conditions in Section 3(a) if You Share all or a substantial portion of the contents of the database.
For the avoidance of doubt, this Section 4 supplements and does not replace Your obligations under this Public License where the Licensed Rights include other Copyright and Similar Rights.
Section 5 Disclaimer of Warranties and Limitation of Liability.
Unless otherwise separately undertaken by the Licensor, to the extent possible, the Licensor offers the Licensed Material as-is and as-available, and makes no representations or warranties of any kind concerning the Licensed Material, whether express, implied, statutory, or other. This includes, without limitation, warranties of title, merchantability, fitness for a particular purpose, non-infringement, absence of latent or other defects, accuracy, or the presence or absence of errors, whether or not known or discoverable. Where disclaimers of warranties are not allowed in full or in part, this disclaimer may not apply to You.
To the extent possible, in no event will the Licensor be liable to You on any legal theory (including, without limitation, negligence) or otherwise for any direct, special, indirect, incidental, consequential, punitive, exemplary, or other losses, costs, expenses, or damages arising out of this Public License or use of the Licensed Material, even if the Licensor has been advised of the possibility of such losses, costs, expenses, or damages. Where a limitation of liability is not allowed in full or in part, this limitation may not apply to You.
The disclaimer of warranties and limitation of liability provided above shall be interpreted in a manner that, to the extent possible, most closely approximates an absolute disclaimer and waiver of all liability.
Section 6 Term and Termination.
This Public License applies for the term of the Copyright and Similar Rights licensed here. However, if You fail to comply with this Public License, then Your rights under this Public License terminate automatically.
Where Your right to use the Licensed Material has terminated under Section 6(a), it reinstates:
automatically as of the date the violation is cured, provided it is cured within 30 days of Your discovery of the violation; or
upon express reinstatement by the Licensor.
For the avoidance of doubt, this Section 6(b) does not affect any right the Licensor may have to seek remedies for Your violations of this Public License.
For the avoidance of doubt, the Licensor may also offer the Licensed Material under separate terms or conditions or stop distributing the Licensed Material at any time; however, doing so will not terminate this Public License.
Sections 1, 5, 6, 7, and 8 survive termination of this Public License.
Section 7 Other Terms and Conditions.
The Licensor shall not be bound by any additional or different terms or conditions communicated by You unless expressly agreed.
Any arrangements, understandings, or agreements regarding the Licensed Material not stated herein are separate from and independent of the terms and conditions of this Public License.
Section 8 Interpretation.
For the avoidance of doubt, this Public License does not, and shall not be interpreted to, reduce, limit, restrict, or impose conditions on any use of the Licensed Material that could lawfully be made without permission under this Public License.
To the extent possible, if any provision of this Public License is deemed unenforceable, it shall be automatically reformed to the minimum extent necessary to make it enforceable. If the provision cannot be reformed, it shall be severed from this Public License without affecting the enforceability of the remaining terms and conditions.
No term or condition of this Public License will be waived and no failure to comply consented to unless expressly agreed to by the Licensor.
Nothing in this Public License constitutes or may be interpreted as a limitation upon, or waiver of, any privileges and immunities that apply to the Licensor or You, including from the legal processes of any jurisdiction or authority.

View File

@ -1,23 +1,21 @@
# Zipcall - Decentralized Video Chat
# Zipcall - Acquired at 250k users
[![Author](https://img.shields.io/badge/Author-ianramzy-brightgreen.svg)](https://ianramzy.com)
![License: CC-NC](https://img.shields.io/badge/License-CCNC-blue.svg)
[![Donate](https://img.shields.io/badge/Donate-PayPal-brightgreen.svg)](https://paypal.me/ianramzy)
[![Repo Link](https://img.shields.io/badge/Repo-Link-black.svg)](https://github.com/ianramzy/decentralized-video-chat)
[![code style: prettier](https://img.shields.io/badge/code_style-prettier-ff69b4.svg?)](https://github.com/prettier/prettier)
[![Join the chat at https://gitter.im/zipcall](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/zipcall)
# https://zipcall.io
# Source code has been removed from this repository as a result of the acquisition.
Decentralized video chat platform powered by WebRTC using Twilio STUN/TURN infrastructure.
Zipcall provides video quality and latency simply not available with traditional
Decentralized video chat platform with video quality and latency simply not available with traditional
technology.
![screenshot](public/images/readmecall.png "Video Calling")
![screenshot](images/readmecall.png "Video Calling")
## Features
<img align="right" width="400" height="auto" src="public/images/preview.gif">
<img align="right" width="400" height="auto" src="images/preview.gif">
- Screen sharing
- Picture in picture
@ -26,45 +24,4 @@ technology.
- Auto-scaling video quality
- No download required, entirely browser based
- Direct peer to peer connection ensures lowest latency
- Single use disposable chat rooms
## Quick start
- You will need to have Node.js installed, this project has been tested with Node version 10.X and 12.X
- Clone this repo
```
git clone https://github.com/ianramzy/decentralized-video-chat
cd decentralized-video-chat
```
#### Set up credentials
- Rename .env.template to .env
- Sign up for free twilio account https://www.twilio.com/login
- Get your Account SID and Auth Token from the Twillio console
- Fill in your credentials in the .env file
#### Install dependencies
```
npm install
```
#### Start the server
```
npm start
```
- Open `localhost:3000` in browser
- If you want to use a client on another computer/network, make sure you publish your server on an HTTPS connection.
You can use a service like [ngrok](https://ngrok.com/) for that.
## Contributing
Pull Requests are welcome!
Please run prettier on all of your PRs before submitting, this can be done with `prettier --write` in the project directory
For communication we use Gitter Chat which can be found here: [![Join the chat at https://gitter.im/zipcall](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/zipcall)
- Single use disposable chat rooms

View File

Before

Width:  |  Height:  |  Size: 2.2 MiB

After

Width:  |  Height:  |  Size: 2.2 MiB

View File

Before

Width:  |  Height:  |  Size: 56 KiB

After

Width:  |  Height:  |  Size: 56 KiB

View File

Before

Width:  |  Height:  |  Size: 358 KiB

After

Width:  |  Height:  |  Size: 358 KiB

1217
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -1,22 +0,0 @@
{
"name": "video-chat2",
"version": "1.0.0",
"description": "",
"main": "server.js",
"scripts": {
"start": "node server.js",
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "See License",
"dependencies": {
"dotenv": "^8.1.0",
"express": "^4.17.1",
"heroku-ssl-redirect": "0.0.4",
"socket.io": "^2.2.0",
"twilio": "^3.34.0"
},
"devDependencies": {
"prettier": "2.0.2"
}
}

View File

@ -1,138 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<!-- Global site tag (gtag.js) - Google Analytics -->
<script
async
src="https://www.googletagmanager.com/gtag/js?id=UA-162048272-1"
></script>
<script>
window.dataLayer = window.dataLayer || [];
function gtag() {
dataLayer.push(arguments);
}
gtag("js", new Date());
gtag("config", "UA-162048272-1");
</script>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Zipcall</title>
<link rel="shortcut icon" href="/images/logo.svg" />
<link rel="stylesheet" href="../css/chat.css" />
<link rel="stylesheet" href="../css/snackbar.css" />
<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/jqueryui/1.11.4/jquery-ui.min.js"></script>
<script src="/js/jquery.ui.touch-punch.js"></script>
<meta property="og:title" content="Join your friends call - Zipcall" />
<meta
property="og:description"
content="Click the link to join this call using Zipcall"
/>
<meta property="og:image" content="https://zipcall.io/images/preview.png" />
<meta property="og:url" content="https://zipcall.io/" />
</head>
<body id="body" onresize="windowResized()">
<div id="header">
<a target="_blank" href="/">
<img src="/images/logo.svg" alt="Neon" width="48" height="48" />
<p>Zipcall</p>
</a>
</div>
<p id="remote-video-text"></p>
<video id="remote-video" autoplay playsinline></video>
<div id="moveable">
<p id="local-video-text">No webcam input</p>
<video id="local-video" autoplay muted playsinline></video>
</div>
<div id="entire-chat">
<div id="chat-zone">
<div class="chat-messages"></div>
</div>
<form class="compose">
<input type="text" placeholder="Type a message" />
</form>
</div>
<div class="multi-button">
<div class="buttonContainer">
<button class="hoverButton" onclick="{muteMicrophone()}">
<i id="mic-icon" class="fas fa-microphone fa-xs"></i>
</button>
<div class="HoverState" id="mic-text">Mute</div>
</div>
<!-- <div class="buttonContainer">-->
<!-- <button class="hoverButton" onclick="{openFullscreen()}">-->
<!-- <i class="fas fa-compress fa-xs"></i>-->
<!-- </button>-->
<!-- <div class="HoverState">Fullscreen</div>-->
<!-- </div>-->
<div class="buttonContainer">
<button class="hoverButton" onclick="{pauseVideo()}">
<i class="fas fa-video fa-xs" id="video-icon"></i>
</button>
<div class="HoverState" id="video-text">Pause Video</div>
</div>
<div class="buttonContainer">
<button class="hoverButton" id="share-button" onclick="{swap()}">
<i id="swap-icon" class="fas fa-desktop fa-xs"></i>
</button>
<div class="HoverState" id="swap-text">Share Screen</div>
</div>
<div class="buttonContainer">
<button class="hoverButton" onclick="{toggleChat()}">
<i id="chat-icon" class="fas fa-comment fa-xs"></i>
</button>
<div class="HoverState" id="chat-text">Show Chat</div>
</div>
<div class="buttonContainer">
<button
class="hoverButton"
id="pip-button"
onclick="{togglePictureInPicture()}"
>
<i class="fas fa-external-link-alt fa-xs"></i>
</button>
<div class="HoverState" id="pip-text">Toggle Picture in Picture</div>
</div>
<div class="buttonContainer">
<button class="hoverButton" onclick="{requestToggleCaptions()}">
<i class="fas fa-closed-captioning fa-xs"></i>
</button>
<div class="HoverState" id="caption-button-text">
Start Live Caption
</div>
</div>
<div class="buttonContainer">
<button
class="hoverButton"
onclick="{window.location.href = '/newcall'}"
>
<i class="fas fa-phone-slash fa-xs"></i>
</button>
<div class="HoverState">End Call</div>
</div>
</div>
<script src="https://webrtc.github.io/adapter/adapter-latest.js"></script>
<script src="/socket.io/socket.io.js"></script>
<script src="../js/snackbar.js"></script>
<script src="../js/autolink.js"></script>
<script src="https://cdn.rawgit.com/muaz-khan/DetectRTC/master/DetectRTC.js"></script>
<script id="chatJS" src="../js/chat.js"></script>
</body>
</html>

View File

@ -1,572 +0,0 @@
@import url("https://fonts.googleapis.com/css?family=Fira+Sans:600|Heebo:400,500,700&display=swap");
/*Fade in page on load*/
@-webkit-keyframes fadeIn {
from {
opacity: 0;
}
to {
opacity: 1;
}
}
@-moz-keyframes fadeIn {
from {
opacity: 0;
}
to {
opacity: 1;
}
}
@keyframes fadeIn {
from {
opacity: 0;
}
to {
opacity: 1;
}
}
/* End Fade in page on load*/
body {
background: #16171b;
margin: 0;
padding: 0;
opacity: 0; /* make things invisible upon start */
-webkit-animation: fadeIn ease-in 1;
-moz-animation: fadeIn ease-in 1;
animation: fadeIn ease-in 1;
-webkit-animation-fill-mode: forwards;
-moz-animation-fill-mode: forwards;
animation-fill-mode: forwards;
-webkit-animation-duration: 0.3s;
-moz-animation-duration: 0.3s;
animation-duration: 0.3s;
overflow: hidden;
}
video {
background: #16171a;
}
#header {
position: absolute;
color: white;
font-family: "Fira Sans", sans-serif;
font-weight: 600;
font-size: 1rem;
white-space: nowrap;
top: 20px;
left: 20px;
float: left;
}
#header p,
img {
float: left;
padding: 7px;
}
#header,
a {
color: white;
text-decoration: none;
}
/*Moveable local video id*/
#moveable {
z-index: 100;
position: absolute;
width: 15%;
cursor: move;
}
/*Text inside local video*/
#moveable p {
z-index: 101;
position: absolute;
color: white;
font-family: "Heebo", sans-serif;
white-space: nowrap;
top: 50%;
left: 50%;
-ms-transform: translate(-50%, -50%);
transform: translate(-50%, -50%);
font-weight: bold;
background: rgba(0, 0, 0, 0.12);
padding: 10px;
border-radius: 5px;
}
#local-video {
width: 100%;
height: auto;
border-radius: 10px;
-webkit-transform: scaleX(-1);
transform: scaleX(-1);
background: #16171a;
}
/*caption text*/
#remote-video-text {
box-sizing: border-box;
margin: 0;
width: 65vw;
position: absolute;
top: calc(80%);
left: 20vw;
z-index: 1;
color: white;
font-family: "Heebo", sans-serif;
font-size: 1.2rem;
font-weight: bold;
text-align: left;
background: rgba(0, 0, 0, 0.2);
border-radius: 0 0 10px 10px;
padding: 10px;
}
#remote-video {
padding: 0;
margin: 0;
position: absolute;
top: 50%;
left: 50%;
-ms-transform: translate(-50%, -50%);
transform: translate(-50%, -50%);
width: 65%;
height: auto;
max-height: 100%;
max-width: 100%;
border-radius: 10px;
background-image: url(../images/loader.gif);
background-size: 400px auto;
background-repeat: no-repeat;
background-position: center center;
}
#remote-video.fullscreen {
width: 100%;
}
/*Buttons*/
.multi-button button {
border: none;
font-size: 1.5rem;
transition: all 0.3s ease-in-out;
color: gray;
background: transparent;
cursor: pointer;
padding: 7px;
border-radius: 5px;
}
button:focus {
outline: none;
}
button:hover {
color: white;
}
.multi-button {
position: absolute;
left: calc(7.5vw - 40px);
top: 50%;
-ms-transform: translate(0%, -50%);
transform: translate(0%, -50%);
z-index: 999;
border-radius: 10px;
background: #16171a;
box-shadow: 9px 9px 16px #0a0b0c, -9px -9px 16px #222328;
padding: 15px;
display: flex;
flex-direction: column;
justify-content: space-around;
/* grid-gap: 0.2rem; */
width: 40px;
}
.HoverState {
color: white;
font-family: "Heebo", sans-serif;
font-size: 0.8rem;
position: absolute;
left: 60px;
white-space: nowrap;
top: 0px;
font-weight: bold;
background: #16171a;
padding: 10px;
border-radius: 10px;
}
.buttonContainer {
position: relative;
margin: 0 auto;
}
/*.fa-phone-slash {*/
/* color: #470000;*/
/*}*/
/*End buttons*/
/*Text chat*/
#entire-chat {
position: absolute;
height: 100%;
right: 0;
width: 17.5vw;
padding: 0;
}
.compose {
width: calc(17.5vw - 40px);
height: 60px;
font-family: "Heebo", sans-serif;
position: fixed;
bottom: 0;
right: 0;
z-index: 100;
border-radius: 20px;
box-shadow: 6px 6px 12px #030506, -6px -6px 12px #292a30;
margin: 20px;
box-sizing: border-box;
padding: 16px;
background: #1c1d22;
overflow-x: hidden;
overflow: -moz-scrollbars-none;
-ms-overflow-style: none;
scrollbar-width: none;
}
.compose input {
/*font-family: inherit;*/
font-size: 0.8rem;
border: none;
width: 100%;
height: calc(100% - 5px);
resize: none;
outline: none;
background-color: inherit;
color: white;
}
.compose input::placeholder {
color: white;
font-size: 0.8rem;
}
#chat-zone {
padding-top: 20px;
box-sizing: border-box;
position: absolute;
height: 100%;
right: 0;
width: 17.5vw;
overflow: scroll;
font-family: "Heebo", sans-serif;
font-size: 0.8rem;
}
#chat-zone::-webkit-scrollbar {
width: 0 !important;
}
#chat-zone .chat-messages .message-item {
position: relative;
display: flex;
flex-direction: column;
align-items: flex-start;
justify-content: flex-end;
padding: 0 16px 4px;
margin-bottom: 10px;
}
.chat-messages {
overflow-x: hidden;
padding-bottom: 80px;
overflow: -moz-scrollbars-none;
}
#chat-zone .chat-messages .message-item.customer {
padding-left: 40px;
}
/*received messages*/
#chat-zone .message-item.moderator .message-bloc {
background-color: rgb(29, 30, 33);
color: #fff;
position: relative;
display: flex;
align-items: center;
justify-content: center;
padding: 12px;
max-width: 100%;
border-radius: 20px 20px 20px 5px;
box-shadow: 6px 6px 12px #030506, -6px -6px 12px #23242a;
}
/*sent messages*/
#chat-zone .message-item.customer .message-bloc {
background-color: rgb(47, 48, 52);
color: #fff;
border-radius: 20px 20px 5px 20px;
box-shadow: 6px 6px 12px #030506, -6px -6px 12px #22232a;
}
#chat-zone .chat-messages .message-item.customer .message-bloc {
margin-left: auto;
}
#chat-zone .chat-messages .message-item .message-bloc {
position: relative;
display: flex;
align-items: center;
justify-content: center;
padding: 12px;
max-width: 100%;
}
.message {
word-break: break-all;
}
.message a {
text-decoration: underline;
}
.cssanimation {
animation-duration: 1s;
animation-fill-mode: both;
}
.fadeInBottom {
animation-name: fadeInBottom;
}
@keyframes fadeInBottom {
from {
opacity: 0;
transform: translateY(200%);
}
to {
opacity: 1;
}
}
/*End text chat*/
/* Begin mobile layout */
@media (max-width: 640px) {
/* @media (min-width: 320px) and (max-width: 480px) { */
html,
body {
width: 100%;
height: 100%;
font-size: 1em;
}
#header {
z-index: 5;
}
#header img {
width: auto;
height: 2rem;
}
#header p {
margin: 0;
line-height: 2rem;
}
#remote-video {
/* width: 75vw;
height: calc((16/9) * 75vw); */
width: 100%;
height: 100%;
/* border: 3px solid red; */
}
#moveable {
position: fixed;
top: 5rem;
left: 5rem;
min-width: 20%;
min-height: 10%;
width: initial;
height: initial;
max-width: 25%;
}
#moveable #local-video {
width: auto;
height: auto;
max-width: 100%;
max-height: 100%;
}
#moveable p {
text-align: center;
z-index: 101;
position: absolute;
color: white;
font-family: "Heebo", sans-serif;
white-space: pre-wrap;
top: 50%;
left: 50%;
-ms-transform: translate(-50%, -50%);
transform: translate(-50%, -50%);
font-weight: bold;
font-size: 1rem;
background: rgba(0, 0, 0, 0.12);
padding: 10px;
border-radius: 5px;
margin: 0;
}
#remote-video-text {
position: fixed;
top: 60% !important;
bottom: initial;
left: initial;
width: 80%;
height: auto;
margin: 0;
margin-left: 10%;
text-align: center;
}
.multi-button {
position: fixed;
left: 0;
top: initial;
bottom: 0;
width: 80vw;
height: 3rem;
margin: 0 10vw;
-ms-transform: translate(0%, 0%);
transform: translate(0%, 0%);
z-index: 999;
box-shadow: none;
border-radius: 10px;
padding: 0;
/* display: flex; */
flex-direction: row;
/* overflow: hidden; */
}
.buttonContainer {
position: relative;
height: 100%;
font-size: 3rem;
display: flex;
flex-direction: column;
align-items: center;
min-width: 0;
width: 100%;
margin: 0;
/* line-height: 1.5rem; */
}
.multi-button button {
position: relative;
width: 100%;
border: none;
font-size: 2rem;
transition: all 0.3s ease-in-out;
color: gray;
background: transparent;
cursor: pointer;
padding: 7px;
border-radius: 5px;
}
.HoverState {
display: none !important;
}
.buttonContainer:nth-child(3),
.buttonContainer:nth-child(5) {
display: none;
}
#entire-chat {
position: absolute;
top: 3rem;
right: 0;
height: calc(100% - 3rem - 3rem);
width: 100vw;
/* padding: 1rem 0; */
padding: 0;
/* border: 3px solid green; */
text-align: center;
/* background: #16171a; */
}
#chat-zone {
position: relative;
padding-top: 20px;
width: 100%;
height: calc(100% - 2rem);
margin-left: 0;
/* box-shadow: 4px 4px 12px #030506, -4px -4px 12px #292a30; */
/* border: 5px solid blue */
border-radius: 10px;
/* background: #16171a; */
}
#chat-zone .message-item.moderator .message-bloc,
#chat-zone .message-item.customer .message-bloc {
box-shadow: none;
}
.compose {
position: absolute;
font-size: 0.8rem;
left: 10%;
right: initial;
/* bottom: calc(3rem + 2rem); */
bottom: 0;
width: 80%;
height: 2rem;
margin: 0.5rem 0;
padding: 0;
box-shadow: none;
}
.compose input {
width: 90%;
height: 2rem;
line-height: 2rem;
}
.compose input::placeholder {
color: white;
}
}
/*Hide video controls on mobile*/
/*todo: still buggy on iOS, play/pause button pops up on load for iOS,
goes away after you press pause then play again*/
video ::-webkit-media-controls-panel {
display: none !important;
-webkit-appearance: none;
}
video ::--webkit-media-controls-play-button {
display: none !important;
-webkit-appearance: none;
}
video ::-webkit-media-controls-start-playback-button {
display: none !important;
-webkit-appearance: none;
}
/* End mobile layout */

File diff suppressed because one or more lines are too long

View File

@ -1,27 +0,0 @@
@media (max-width: 640px) {
.section:first-of-type {
min-height: 0;
}
section:first-of-type .hero-inner {
padding-top: 1rem;
padding-bottom: 0;
}
section:first-of-type .hero-inner .split-item {
padding: 0;
}
section:nth-of-type(2) {
margin-top: 2rem;
}
section:nth-of-type(2) .section-inner {
padding-top: 1rem;
padding-bottom: 0.5rem;
}
section:nth-of-type(2) .section-inner .cta-slogan {
margin-bottom: 1rem;
}
}

View File

@ -1,143 +0,0 @@
.snackbar-container {
box-shadow: 9px 9px 16px #0a0b0c, -9px -9px 16px #222328;
transition: all 0.5s ease;
transition-property: top, right, bottom, left, opacity;
font-family: "Heebo", sans-serif;
font-size: 14px;
min-height: 14px;
position: fixed;
display: flex;
justify-content: space-between;
align-items: center;
color: #b4b4b4;
line-height: 22px;
padding: 18px 24px;
bottom: -100px;
top: -100px;
opacity: 0;
z-index: 9999;
background-color: #376df9;
background: linear-gradient(100deg, #376df9 0, #ff5fa0 75%, #ffc55a 100%);
}
.snackbar-container .action {
background: white;
padding: 7px;
border-radius: 3px;
display: inline-block;
border: none;
font-size: inherit;
text-transform: uppercase;
color: #000000;
margin: 0 0 0 24px;
/*padding: 0;*/
min-width: min-content;
cursor: pointer;
}
@media (min-width: 640px) {
.snackbar-container {
min-width: 288px;
max-width: 568px;
display: inline-flex;
border-radius: 5px;
margin: 24px;
}
}
/* @media (max-width: 640px) {
.snackbar-container {
left: 0;
right: 0;
width: 100%;
}
} */
.snackbar-pos.bottom-center {
top: auto !important;
bottom: 0;
left: 50%;
transform: translate(-50%, 0);
}
.snackbar-pos.bottom-left {
top: auto !important;
bottom: 0;
left: 0;
}
.snackbar-pos.bottom-right {
top: auto !important;
bottom: 0;
right: 0;
}
.snackbar-pos.top-left {
bottom: auto !important;
top: 0;
left: 0;
}
.snackbar-pos.top-center {
bottom: auto !important;
top: 0;
left: 50%;
transform: translate(-50%, 0);
}
.snackbar-pos.top-right {
bottom: auto !important;
top: 0;
right: 0;
}
/* Mobile Styles Start */
@media (max-width: 640px) {
.snackbar-container {
position: fixed;
top: 5rem;
bottom: initial;
left: calc(10vw - 0.5rem);
right: initial;
display: flex;
justify-content: space-between;
width: 80vw !important;
min-width: 80vw;
max-width: 80vw;
height: auto;
margin: 0;
margin-top: 1rem;
padding: 0.5rem;
word-wrap: break-word;
line-height: 1.2rem;
font-size: 1rem;
}
.snackbar-container p {
width: 80%;
}
.snackbar-container .action {
width: 15%;
padding: 0.2rem;
border-radius: 10px;
display: inline-block;
border: none;
font-size: 1rem;
text-transform: uppercase;
color: #000000;
margin: 0;
/*padding: 0;*/
cursor: pointer;
}
.snackbar-pos.bottom-center,
.snackbar-pos.top-center {
left: calc(10vw - 0.5rem);
transform: none;
}
}
/* Mobile Styles End */

View File

@ -1 +0,0 @@
<svg width="124" height="24" xmlns="http://www.w3.org/2000/svg"><path d="M63.849 11.694c-1.023 0-1.76.326-2.507.657v7.507c.716.066 1.126.066 1.805.066 2.454 0 2.79-1.092 2.79-2.616v-3.585c0-1.125-.384-2.029-2.088-2.029zm-16.295-.41c-1.702 0-2.09.908-2.09 2.033v.631h4.179v-.631c0-1.125-.389-2.033-2.089-2.033zm-31.566 7.813c0 .89.432 1.352 1.386 1.352 1.022 0 1.628-.324 2.375-.657v-1.78h-2.237c-1.059 0-1.524.19-1.524 1.085zM79.7 11.694c-1.705 0-2.296.904-2.296 2.03v4.106c0 1.129.59 2.035 2.296 2.035 1.7 0 2.296-.906 2.296-2.035v-4.107c0-1.125-.596-2.029-2.296-2.029zM7.632 23.702H2.619V11.917H.115v-4.06H2.62v-2.44C2.62 2.104 4.033.134 8.05.134h3.345v4.062h-2.09c-1.565 0-1.668.568-1.668 1.627l-.006 2.033h3.787l-.443 4.06H7.632v11.786zm17.13.031h-4.177l-.18-1.026a9.802 9.802 0 01-4.734 1.192c-3.063 0-4.694-1.988-4.694-4.737 0-3.244 1.903-4.402 5.307-4.402h3.465v-.701c0-1.656-.196-2.142-2.817-2.142h-4.286l.419-4.06h4.685c5.751 0 7.012 1.764 7.012 6.235v9.641zm14.206-11.518c-2.6-.433-3.346-.528-4.597-.528-2.246 0-2.925.481-2.925 2.335v3.506c0 1.853.679 2.337 2.925 2.337 1.251 0 1.998-.097 4.597-.532v3.961c-2.277.496-3.76.627-5.014.627-5.381 0-7.52-2.75-7.52-6.72v-2.845c0-3.975 2.139-6.729 7.52-6.729 1.254 0 2.737.13 5.014.629v3.959zM54.654 17.2h-9.191v.328c0 1.853.68 2.337 2.925 2.337 2.02 0 3.252-.097 5.847-.532v3.961c-2.503.496-3.807.627-6.262.627-5.382 0-7.522-2.75-7.522-6.72v-3.253c0-3.475 1.587-6.32 7.102-6.32 5.515 0 7.101 2.812 7.101 6.32V17.2zm16.294.076c0 3.838-1.129 6.637-7.97 6.637-2.471 0-3.92-.21-6.647-.618V1.355l5.01-.813v7.675c1.084-.39 2.485-.59 3.76-.59 5.012 0 5.847 2.183 5.847 5.69v3.959zm16.063.083c0 3.311-1.407 6.523-7.295 6.523-5.891 0-7.325-3.212-7.325-6.523v-3.197c0-3.313 1.434-6.525 7.325-6.525 5.888 0 7.295 3.212 7.295 6.525v3.197zm16.052 0c0 3.311-1.41 6.523-7.296 6.523-5.891 0-7.325-3.212-7.325-6.523v-3.197c0-3.313 1.434-6.525 7.325-6.525 5.887 0 7.296 3.212 7.296 6.525v3.197zm16.472 6.343h-5.431l-4.594-7.448v7.448h-5.012V1.354l5.012-.812v14.387l4.594-7.073h5.431l-5.014 7.719 5.014 8.127zM95.75 11.694c-1.703 0-2.294.904-2.294 2.03v4.106c0 1.129.591 2.035 2.294 2.035 1.7 0 2.301-.906 2.301-2.035v-4.107c0-1.125-.601-2.029-2.301-2.029zm26.646 9.229c.844 0 1.516.668 1.516 1.503 0 .848-.672 1.51-1.522 1.51a1.511 1.511 0 01-1.532-1.51c0-.835.686-1.503 1.532-1.503h.006zm-.006.234c-.68 0-1.237.568-1.237 1.27 0 .713.557 1.274 1.243 1.274.687.007 1.235-.56 1.235-1.268s-.548-1.276-1.235-1.276h-.006zm-.288 2.144h-.275v-1.677c.144-.02.282-.04.488-.04.261 0 .432.054.537.127.101.074.156.187.156.347 0 .221-.15.354-.336.408v.013c.151.027.254.16.289.406.04.261.082.361.108.416h-.288c-.04-.055-.082-.208-.117-.429-.04-.213-.15-.293-.37-.293h-.192v.722zm0-.928h.2c.225 0 .417-.081.417-.289 0-.147-.11-.293-.418-.293-.09 0-.152.007-.2.013v.569z" fill="#6A6F82"/></svg>

Before

Width:  |  Height:  |  Size: 2.7 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 6.3 KiB

View File

@ -1 +0,0 @@
<svg width="125" height="39" xmlns="http://www.w3.org/2000/svg"><path d="M65.879 9.8a2.533 2.533 0 01-2.539 2.537 2.532 2.532 0 01-2.538-2.538 2.508 2.508 0 012.538-2.537c1.446.039 2.539 1.171 2.539 2.537zm-10.466 5.114v.624s-1.21-1.562-3.787-1.562c-4.256 0-7.576 3.24-7.576 7.73 0 4.45 3.28 7.73 7.576 7.73 2.616 0 3.787-1.601 3.787-1.601v.663c0 .313.235.546.547.546h3.163V14.365H55.96a.561.561 0 00-.547.549zm0 9.407c-.585.86-1.757 1.601-3.162 1.601-2.5 0-4.413-1.561-4.413-4.216 0-2.655 1.914-4.216 4.413-4.216 1.367 0 2.616.78 3.162 1.6v5.231zm6.053-9.954h3.749v14.678h-3.749V14.367zm55.998-.391c-2.578 0-3.788 1.562-3.788 1.562V7.301h-3.749v21.744h3.163a.558.558 0 00.547-.546v-.664s1.21 1.6 3.787 1.6c4.257 0 7.576-3.277 7.576-7.728 0-4.45-3.319-7.731-7.536-7.731zm-.625 11.907c-1.445 0-2.577-.741-3.163-1.6V19.05c.586-.78 1.835-1.6 3.163-1.6 2.499 0 4.412 1.561 4.412 4.216 0 2.654-1.913 4.216-4.412 4.216zm-8.864-5.543v8.744h-3.75V20.77c0-2.42-.78-3.396-2.888-3.396-1.132 0-2.304.585-3.047 1.445v10.228h-3.748v-14.68h2.967c.313 0 .547.274.547.548v.624c1.094-1.132 2.538-1.562 3.983-1.562 1.64 0 3.007.47 4.1 1.406 1.328 1.093 1.836 2.498 1.836 4.958zm-22.533-6.364c-2.576 0-3.787 1.562-3.787 1.562V7.301h-3.749v21.744h3.163a.559.559 0 00.547-.546v-.664s1.21 1.6 3.787 1.6c4.257 0 7.576-3.277 7.576-7.728.04-4.451-3.28-7.731-7.537-7.731zm-.625 11.907c-1.444 0-2.576-.741-3.162-1.6V19.05c.586-.78 1.835-1.6 3.162-1.6 2.5 0 4.413 1.561 4.413 4.216 0 2.654-1.913 4.216-4.413 4.216zM74.665 13.976c1.132 0 1.718.196 1.718.196v3.474s-3.124-1.055-5.076 1.171v10.267h-3.75V14.367h3.164c.312 0 .546.273.546.546v.625c.704-.82 2.227-1.562 3.398-1.562zM35.733 27.718c-.195-.468-.39-.976-.586-1.406-.313-.702-.625-1.366-.898-1.99l-.039-.04a406.922 406.922 0 00-8.63-17.644l-.117-.235c-.32-.608-.633-1.22-.937-1.835-.39-.703-.78-1.444-1.406-2.147C21.87.859 20.074 0 18.161 0c-1.953 0-3.71.86-4.998 2.342-.586.703-1.016 1.444-1.406 2.148a84.724 84.724 0 01-.936 1.835l-.118.234c-3.007 5.856-5.935 11.79-8.63 17.645l-.04.078c-.272.625-.585 1.289-.898 1.99-.195.43-.39.899-.585 1.406-.508 1.444-.664 2.81-.468 4.217a8.297 8.297 0 005.076 6.48c1.016.43 2.07.625 3.163.625.313 0 .703-.039 1.016-.078 1.288-.156 2.616-.585 3.905-1.327 1.6-.898 3.124-2.186 4.842-4.06 1.718 1.874 3.28 3.162 4.842 4.06 1.29.742 2.616 1.17 3.905 1.327.312.04.703.078 1.016.078 1.093 0 2.186-.195 3.162-.625 2.734-1.094 4.647-3.591 5.077-6.48.31-1.366.154-2.732-.353-4.177zm-17.611 2.03c-2.11-2.655-3.476-5.153-3.944-7.26-.195-.899-.235-1.68-.117-2.382a3.78 3.78 0 01.625-1.64c.742-1.054 1.991-1.718 3.436-1.718 1.445 0 2.734.625 3.437 1.718.312.468.547 1.015.625 1.64.117.703.078 1.522-.117 2.381-.47 2.069-1.837 4.568-3.945 7.26zm15.58 1.835a5.802 5.802 0 01-3.553 4.568c-.937.39-1.953.507-2.968.39-.976-.118-1.953-.43-2.967-1.015-1.406-.782-2.812-1.991-4.452-3.787 2.577-3.162 4.139-6.051 4.725-8.627a9.765 9.765 0 00.195-3.32 6.329 6.329 0 00-1.054-2.654c-1.212-1.757-3.242-2.771-5.507-2.771-2.264 0-4.295 1.054-5.505 2.771a6.335 6.335 0 00-1.055 2.655 8.107 8.107 0 00.195 3.319c.586 2.576 2.187 5.504 4.725 8.666-1.601 1.796-3.046 3.006-4.452 3.787-1.015.586-1.991.898-2.967 1.015a6.25 6.25 0 01-2.968-.39 5.802 5.802 0 01-3.553-4.568 6.457 6.457 0 01.351-3.045c.117-.39.313-.78.508-1.25.273-.624.585-1.288.898-1.951l.04-.078a425.627 425.627 0 018.59-17.528l.117-.235c.313-.585.625-1.21.937-1.795.313-.625.664-1.211 1.094-1.719.82-.936 1.913-1.444 3.124-1.444 1.21 0 2.304.508 3.124 1.444.43.51.78 1.095 1.093 1.719.313.585.626 1.21.937 1.795l.118.235a516.84 516.84 0 018.552 17.567v.039c.312.626.586 1.328.898 1.953.195.468.39.858.508 1.248.311 1.014.428 1.991.272 3.006z" fill="#6A6F82"/></svg>

Before

Width:  |  Height:  |  Size: 3.6 KiB

View File

@ -1 +0,0 @@
<svg width="150" height="31" xmlns="http://www.w3.org/2000/svg"><g fill="#6A6F82" fill-rule="evenodd"><path d="M150 14.514v-2.647h-3.295V7.75l-.11.034-3.095.945-.061.019v3.118h-4.884V10.13c0-.81.181-1.428.538-1.841.355-.408.863-.615 1.51-.615.465 0 .947.11 1.431.325l.122.054V5.265l-.057-.021c-.452-.162-1.068-.244-1.83-.244-.96 0-1.834.209-2.596.622a4.432 4.432 0 00-1.78 1.757c-.419.751-.631 1.618-.631 2.578v1.91h-2.294v2.647h2.294v11.153h3.293V14.514h4.884v7.088c0 2.919 1.38 4.398 4.1 4.398a6.78 6.78 0 001.4-.155c.488-.105.822-.21 1.018-.322l.043-.026v-2.672l-.134.089a2.309 2.309 0 01-.662.288 2.52 2.52 0 01-.65.11c-.638 0-1.11-.171-1.402-.51-.296-.34-.446-.938-.446-1.773v-6.515H150zm-24.387 8.799c-1.195 0-2.137-.396-2.801-1.175-.669-.783-1.007-1.9-1.007-3.317 0-1.464.338-2.61 1.007-3.406.664-.791 1.598-1.193 2.775-1.193 1.142 0 2.05.383 2.702 1.14.654.762.986 1.898.986 3.379 0 1.498-.312 2.65-.928 3.42-.612.764-1.531 1.152-2.734 1.152zm.147-11.779c-2.28 0-4.092.667-5.383 1.982-1.291 1.315-1.945 3.136-1.945 5.41 0 2.161.638 3.9 1.898 5.165 1.26 1.267 2.975 1.908 5.096 1.908 2.21 0 3.986-.676 5.277-2.009 1.29-1.332 1.945-3.135 1.945-5.356 0-2.195-.614-3.946-1.825-5.204-1.211-1.258-2.915-1.896-5.063-1.896zm-12.638 0c-1.551 0-2.834.396-3.815 1.177-.986.785-1.486 1.815-1.486 3.062 0 .647.108 1.223.32 1.711.214.49.545.921.985 1.283.436.359 1.11.735 2.001 1.117.75.308 1.31.569 1.665.774.347.201.594.404.733.6.135.193.204.457.204.783 0 .927-.696 1.378-2.128 1.378-.53 0-1.136-.11-1.8-.329a6.769 6.769 0 01-1.844-.932l-.136-.098v3.164l.05.023c.466.215 1.053.396 1.746.538a9.423 9.423 0 001.864.215c1.684 0 3.04-.398 4.028-1.183.996-.79 1.5-1.845 1.5-3.135 0-.93-.271-1.728-.807-2.37-.531-.639-1.454-1.225-2.74-1.743-1.026-.41-1.683-.751-1.954-1.013-.261-.253-.394-.61-.394-1.063 0-.401.164-.723.5-.983.339-.262.81-.395 1.401-.395.55 0 1.11.087 1.669.256a5.4 5.4 0 011.457.674l.134.092v-3.001l-.051-.022c-.378-.162-.875-.3-1.48-.412a9.05 9.05 0 00-1.622-.168zM99.236 23.313c-1.195 0-2.138-.396-2.802-1.175-.668-.783-1.006-1.899-1.006-3.317 0-1.464.338-2.61 1.007-3.406.664-.791 1.597-1.193 2.774-1.193 1.142 0 2.05.383 2.702 1.14.655.762.987 1.898.987 3.379 0 1.498-.313 2.65-.929 3.42-.611.764-1.53 1.152-2.733 1.152zm.147-11.779c-2.281 0-4.093.667-5.384 1.982-1.29 1.315-1.945 3.136-1.945 5.41 0 2.162.64 3.9 1.9 5.165C95.213 25.358 96.927 26 99.048 26c2.21 0 3.986-.676 5.277-2.009 1.29-1.332 1.945-3.135 1.945-5.356 0-2.195-.614-3.946-1.825-5.204-1.212-1.258-2.916-1.896-5.063-1.896zm-12.328 2.723v-2.39h-3.253v13.8h3.253v-7.06c0-1.2.273-2.186.811-2.93.531-.737 1.24-1.11 2.104-1.11.293 0 .622.049.978.144.353.095.608.198.759.306l.136.099v-3.273l-.052-.022c-.303-.129-.732-.194-1.274-.194-.818 0-1.55.263-2.176.779-.55.453-.947 1.075-1.251 1.85h-.035zm-9.079-2.723c-1.492 0-2.823.32-3.955.95a6.4 6.4 0 00-2.61 2.676c-.594 1.143-.896 2.478-.896 3.966 0 1.304.293 2.5.871 3.555a6.114 6.114 0 002.435 2.456c1.035.573 2.231.863 3.556.863 1.546 0 2.866-.309 3.924-.917l.043-.024v-2.974l-.137.1a6.12 6.12 0 01-1.591.826c-.575.2-1.1.302-1.56.302-1.276 0-2.3-.399-3.044-1.185-.746-.786-1.123-1.891-1.123-3.281 0-1.4.394-2.533 1.17-3.369.775-.833 1.802-1.256 3.052-1.256 1.069 0 2.11.361 3.096 1.075l.137.098v-3.133l-.044-.025c-.371-.207-.877-.378-1.505-.508a9.008 9.008 0 00-1.819-.195zm-9.701.333h-3.253v13.8h3.253v-13.8zm-1.593-5.879c-.536 0-1.003.182-1.386.542a1.787 1.787 0 00-.581 1.354c0 .529.193.975.575 1.327.379.351.847.529 1.392.529a2.01 2.01 0 001.398-.528 1.73 1.73 0 00.582-1.328c0-.518-.19-.969-.566-1.339-.375-.37-.851-.557-1.414-.557zm-8.117 4.86v14.819h3.32V6.41H57.29l-5.84 14.302L45.782 6.41H41v19.256h3.12v-14.82h.107l5.985 14.82h2.354l5.892-14.818h.107z" fill-rule="nonzero"/><path d="M15 14H0V0h15zm17 0H17V0h15zM15 31H0V17h15zm17 0H17V17h15z"/></g></svg>

Before

Width:  |  Height:  |  Size: 3.7 KiB

View File

@ -1 +0,0 @@
<svg width="113" height="30" xmlns="http://www.w3.org/2000/svg"><g fill="#6A6F82"><path d="M0 5h3.94v8.21h8.31V5h3.946v20.153H12.25V16.77H3.94v8.383H0V5zm28.678 13.589c0 1.687-1.465 3.06-3.264 3.06-1.799 0-3.264-1.373-3.264-3.06V9.912h-3.736v8.677c0 3.62 3.14 6.564 7 6.564s7-2.945 7-6.564V9.912h-3.736v8.677zm14.167-8.575c-1.854 0-3.147.504-4.397 1.655V5H34.7v12.359c0 4.626 3.567 7.794 7.573 7.794 4.454 0 8.357-3.225 8.357-7.57 0-4.29-3.599-7.57-7.784-7.57zm.093 11.886c-2.54 0-4.483-1.99-4.483-4.317s1.943-4.317 4.483-4.317c2.152 0 4.096 1.99 4.096 4.317S45.09 21.9 42.938 21.9zm13.987-11c0-1.768 1.256-2.328 2.63-2.328 1.107 0 2.572.785 3.527 1.738l2.451-2.69c-1.225-1.543-3.705-2.608-5.738-2.608-4.066 0-6.995 2.215-6.995 5.888 0 6.812 8.938 4.652 8.938 8.466 0 1.176-1.225 2.214-2.63 2.214-2.212 0-2.93-1.009-3.946-2.074l-2.72 2.634c1.734 1.991 3.886 3 6.457 3 3.856 0 6.964-2.242 6.964-5.747 0-7.569-8.938-5.214-8.938-8.493zm18.808-1.084c-4.007 0-7.573 3.167-7.573 7.794V30h3.748v-6.7c1.25 1.15 2.543 1.655 4.397 1.655 4.185 0 7.785-3.28 7.785-7.57 0-4.345-3.904-7.569-8.357-7.569zm.666 11.887c-2.54 0-4.483-1.992-4.483-4.318 0-2.327 1.943-4.317 4.483-4.317 2.152 0 4.095 1.99 4.095 4.317 0 2.326-1.943 4.318-4.095 4.318zm35.285.197c-2.211 0-2.84-.897-2.84-2.27v-6.084h3.438v-3.083h-3.437V6.397l-3.795 1.598v12.391c0 3.168 2.33 4.767 5.527 4.767.479 0 1.137-.03 1.496-.112l.927-3.196c-.418.027-.897.055-1.316.055z"/><path d="M100.964 13.775c-.714-1.105-1.718-1.99-2.974-2.658a8.595 8.595 0 00-3.009-.937V6.67c1.097-.42 1.778-1.346 1.778-2.428 0-1.474-1.315-2.668-2.952-2.668-1.639 0-2.976 1.194-2.976 2.668 0 1.082.641 2.009 1.738 2.428v3.513a9.297 9.297 0 00-2.618.738c-1.697-1.16-7.262-4.962-10.517-7.183.078-.25.137-.509.137-.781C79.57 1.323 78.1 0 76.285 0S73 1.323 73 2.956c0 1.632 1.47 2.956 3.287 2.956a3.53 3.53 0 001.686-.43l.687.468 9.44 6.117c-.5.412-.964.88-1.336 1.407-.753 1.072-1.214 2.252-1.214 3.538v.269c0 .903.191 1.756.516 2.557a6.56 6.56 0 001.223 1.91l-3.133 2.825c-.927-.31-1.97-.104-2.668.527a2.16 2.16 0 00-.743 1.615c0 .61.264 1.184.744 1.615a2.67 2.67 0 001.796.67 2.674 2.674 0 001.797-.67 2.16 2.16 0 00.743-1.615c0-.236-.04-.466-.117-.685l3.238-2.913c.444.276.924.508 1.44.708a9.221 9.221 0 003.366.637h.225a8.651 8.651 0 003.842-.874c1.269-.62 2.262-1.468 3.012-2.55.754-1.086 1.169-2.285 1.169-3.604v-.066c0-1.298-.334-2.496-1.036-3.593zm-3.956 6.11c-.879.879-1.89 1.42-3.031 1.42h-.188c-.653 0-1.29-.162-1.915-.457a4.292 4.292 0 01-1.678-1.374c-.452-.576-.698-1.205-.698-1.87V17.4c0-.655.14-1.277.492-1.863A4.23 4.23 0 0191.552 14a4.133 4.133 0 012.163-.587h.074c.716 0 1.394.127 2.034.422a4.181 4.181 0 011.598 1.307c.401.565.64 1.174.717 1.837.012.138.018.28.018.414 0 .9-.383 1.735-1.148 2.492z"/></g></svg>

Before

Width:  |  Height:  |  Size: 2.7 KiB

View File

@ -1 +0,0 @@
<svg width="72" height="72" xmlns="http://www.w3.org/2000/svg"><defs><filter x="-63.9%" y="-63.9%" width="227.8%" height="227.8%" filterUnits="objectBoundingBox" id="a"><feOffset dy="8" in="SourceAlpha" result="shadowOffsetOuter1"/><feGaussianBlur stdDeviation="8" in="shadowOffsetOuter1" result="shadowBlurOuter1"/><feColorMatrix values="0 0 0 0 0.0862745098 0 0 0 0 0.0901960784 0 0 0 0 0.105882353 0 0 0 0.32 0" in="shadowBlurOuter1" result="shadowMatrixOuter1"/><feMerge><feMergeNode in="shadowMatrixOuter1"/><feMergeNode in="SourceGraphic"/></feMerge></filter></defs><g filter="url(#a)" fill="#FFF"><path d="M28 25h19l-3 6H25z"/><path opacity=".64" d="M28 33h19l-3 6H25z"/><path d="M28 41h19l-3 6H25z"/></g></svg>

Before

Width:  |  Height:  |  Size: 718 B

View File

@ -1 +0,0 @@
<svg width="72" height="72" xmlns="http://www.w3.org/2000/svg"><defs><filter x="-63.9%" y="-63.9%" width="227.8%" height="227.8%" filterUnits="objectBoundingBox" id="a"><feOffset dy="8" in="SourceAlpha" result="shadowOffsetOuter1"/><feGaussianBlur stdDeviation="8" in="shadowOffsetOuter1" result="shadowBlurOuter1"/><feColorMatrix values="0 0 0 0 0.0862745098 0 0 0 0 0.0901960784 0 0 0 0 0.105882353 0 0 0 0.32 0" in="shadowBlurOuter1" result="shadowMatrixOuter1"/><feMerge><feMergeNode in="shadowMatrixOuter1"/><feMergeNode in="SourceGraphic"/></feMerge></filter></defs><g filter="url(#a)" fill="#FFF"><rect x="24" y="24" width="14" height="17" rx="1"/><path d="M46.859 31.168L40.3 29.393l-.522 1.931 5.6 1.514-3.399 12.548-11.584-3.131-.521 1.931 12.55 3.393a1 1 0 001.226-.705l3.913-14.48a1 1 0 00-.704-1.226z" opacity=".64"/></g></svg>

Before

Width:  |  Height:  |  Size: 840 B

View File

@ -1 +0,0 @@
<svg width="72" height="72" xmlns="http://www.w3.org/2000/svg"><defs><filter x="-63.9%" y="-63.9%" width="227.8%" height="227.8%" filterUnits="objectBoundingBox" id="a"><feOffset dy="8" in="SourceAlpha" result="shadowOffsetOuter1"/><feGaussianBlur stdDeviation="8" in="shadowOffsetOuter1" result="shadowBlurOuter1"/><feColorMatrix values="0 0 0 0 0.0862745098 0 0 0 0 0.0901960784 0 0 0 0 0.105882353 0 0 0 0.32 0" in="shadowBlurOuter1" result="shadowMatrixOuter1"/><feMerge><feMergeNode in="shadowMatrixOuter1"/><feMergeNode in="SourceGraphic"/></feMerge></filter></defs><g filter="url(#a)" fill="#FFF"><path d="M33 34h-7a1 1 0 01-1-1v-7a1 1 0 011-1h7a1 1 0 011 1v7a1 1 0 01-1 1zm0 13h-7a1 1 0 01-1-1v-7a1 1 0 011-1h7a1 1 0 011 1v7a1 1 0 01-1 1zm4-21h10v2H37z"/><path opacity=".64" d="M37 31h10v2H37zm0 8h10v2H37z"/><path d="M37 44h10v2H37z"/></g></svg>

Before

Width:  |  Height:  |  Size: 854 B

View File

@ -1 +0,0 @@
<svg width="72" height="72" xmlns="http://www.w3.org/2000/svg"><defs><filter x="-63.9%" y="-63.9%" width="227.8%" height="227.8%" filterUnits="objectBoundingBox" id="a"><feOffset dy="8" in="SourceAlpha" result="shadowOffsetOuter1"/><feGaussianBlur stdDeviation="8" in="shadowOffsetOuter1" result="shadowBlurOuter1"/><feColorMatrix values="0 0 0 0 0.0862745098 0 0 0 0 0.0901960784 0 0 0 0 0.105882353 0 0 0 0.32 0" in="shadowBlurOuter1" result="shadowMatrixOuter1"/><feMerge><feMergeNode in="shadowMatrixOuter1"/><feMergeNode in="SourceGraphic"/></feMerge></filter></defs><g filter="url(#a)" fill="#FFF"><path d="M48 36a2.99 2.99 0 00-2-2.816v-3.368A2.993 2.993 0 1042.184 26h-3.368a2.982 2.982 0 00-5.632 0h-3.368A2.993 2.993 0 1026 29.816v3.368a2.982 2.982 0 000 5.632v3.368A2.993 2.993 0 1029.816 46h3.368a2.982 2.982 0 005.632 0h3.368A2.993 2.993 0 1046 42.184v-3.368A2.99 2.99 0 0048 36zm-4 2.816v3.368c-.848.3-1.515.968-1.816 1.816h-3.368a2.982 2.982 0 00-5.632 0h-3.368A2.987 2.987 0 0028 42.184v-3.368a2.982 2.982 0 000-5.632v-3.368A2.987 2.987 0 0029.816 28h3.368a2.982 2.982 0 005.632 0h3.368c.3.848.968 1.515 1.816 1.816v3.368a2.982 2.982 0 000 5.632z"/><circle opacity=".64" cx="36" cy="36" r="3"/></g></svg>

Before

Width:  |  Height:  |  Size: 1.2 KiB

View File

@ -1 +0,0 @@
<svg width="72" height="72" xmlns="http://www.w3.org/2000/svg"><defs><filter x="-63.9%" y="-63.9%" width="227.8%" height="227.8%" filterUnits="objectBoundingBox" id="a"><feOffset dy="8" in="SourceAlpha" result="shadowOffsetOuter1"/><feGaussianBlur stdDeviation="8" in="shadowOffsetOuter1" result="shadowBlurOuter1"/><feColorMatrix values="0 0 0 0 0.0862745098 0 0 0 0 0.0901960784 0 0 0 0 0.105882353 0 0 0 0.32 0" in="shadowBlurOuter1" result="shadowMatrixOuter1"/><feMerge><feMergeNode in="shadowMatrixOuter1"/><feMergeNode in="SourceGraphic"/></feMerge></filter></defs><g filter="url(#a)" fill="#FFF"><path d="M35.406 24.132l-10.82 5.055a.42.42 0 00.001.764l10.905 5.018c.322.148.694.148 1.016 0l10.905-5.018a.42.42 0 00.002-.764l-10.821-5.055a1.403 1.403 0 00-1.188 0z"/><path d="M47.415 35.676l-2.235-1.044a1.216 1.216 0 00-1.023-.003l-7.649 3.52a1.216 1.216 0 01-1.016 0l-7.65-3.52a1.216 1.216 0 00-1.022.003l-2.235 1.044a.42.42 0 00.002.764l10.905 5.017a1.21 1.21 0 001.016 0l10.905-5.017a.42.42 0 00.002-.764z" opacity=".64"/><path d="M47.415 42.108l-2.235-1.044a1.216 1.216 0 00-1.023-.003l-7.649 3.519a1.216 1.216 0 01-1.016 0l-7.65-3.52a1.216 1.216 0 00-1.022.003l-2.235 1.045a.42.42 0 00.002.763l10.905 5.018c.322.148.694.148 1.016 0l10.905-5.018a.42.42 0 00.002-.763z"/></g></svg>

Before

Width:  |  Height:  |  Size: 1.3 KiB

View File

@ -1 +0,0 @@
<svg width="72" height="72" xmlns="http://www.w3.org/2000/svg"><defs><filter x="-63.9%" y="-63.9%" width="227.8%" height="227.8%" filterUnits="objectBoundingBox" id="a"><feOffset dy="8" in="SourceAlpha" result="shadowOffsetOuter1"/><feGaussianBlur stdDeviation="8" in="shadowOffsetOuter1" result="shadowBlurOuter1"/><feColorMatrix values="0 0 0 0 0.0862745098 0 0 0 0 0.0901960784 0 0 0 0 0.105882353 0 0 0 0.32 0" in="shadowBlurOuter1" result="shadowMatrixOuter1"/><feMerge><feMergeNode in="shadowMatrixOuter1"/><feMergeNode in="SourceGraphic"/></feMerge></filter></defs><g filter="url(#a)" fill="#FFF"><path d="M33 47c.008-7.729 6.271-13.992 14-14 .444.004.888.03 1.329.08a11.993 11.993 0 10-15.248 15.249c-.05-.441-.077-.885-.081-1.329z"/><path d="M47 35a11.92 11.92 0 00-11.844 13.844l13.688-13.688c-.61-.1-1.226-.151-1.844-.156z" opacity=".64"/></g></svg>

Before

Width:  |  Height:  |  Size: 860 B

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 151 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 151 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 215 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 215 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 187 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 183 KiB

View File

@ -1 +0,0 @@
<svg width="32" height="32" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><defs><radialGradient cx="44.286%" cy="100%" fx="44.286%" fy="100%" r="120.709%" gradientTransform="matrix(0 -.82759 1 0 -.557 1.367)" id="a"><stop stop-color="#376DF9" offset="0%"/><stop stop-color="#D262B4" offset="46.208%"/><stop stop-color="#FF8D74" offset="77.058%"/><stop stop-color="#FFD4CA" offset="100%"/></radialGradient><radialGradient cx="44.286%" cy="0%" fx="44.286%" fy="0%" r="120.709%" gradientTransform="matrix(0 .82759 -1 0 .443 -.367)" id="c"><stop stop-color="#376DF9" offset="0%"/><stop stop-color="#D262B4" offset="46.208%"/><stop stop-color="#FF8D74" offset="77.058%"/><stop stop-color="#FFD4CA" offset="100%"/></radialGradient><path d="M20 29c8-6.915 12-12.582 12-17 0-6.627-5.373-12-12-12S8 5.373 8 12c0 4.418 4 10.085 12 17z" id="b"/><path d="M12 32c8-6.915 12-12.582 12-17 0-6.627-5.373-12-12-12S0 8.373 0 15c0 4.418 4 10.085 12 17z" id="d"/></defs><g fill="none" fill-rule="evenodd"><use fill="url(#a)" opacity=".88" xlink:href="#b"/><use fill="url(#c)" opacity=".48" transform="matrix(1 0 0 -1 0 35)" xlink:href="#d"/></g></svg>

Before

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 53 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.4 KiB

View File

@ -1 +0,0 @@
<svg width="712" height="400" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><defs><linearGradient x1="50%" y1="0%" x2="50%" y2="100%" id="e"><stop stop-color="#FFF" stop-opacity=".32" offset="0%"/><stop stop-color="#FFF" stop-opacity="0" offset="100%"/></linearGradient><linearGradient x1="77.999%" y1="9.763%" x2="24.434%" y2="90.469%" id="h"><stop stop-color="#12141D" stop-opacity=".72" offset="0%"/><stop stop-color="#12141D" offset="100%"/></linearGradient><filter x="-70%" y="-50%" width="240%" height="240%" filterUnits="objectBoundingBox" id="f"><feOffset dy="16" in="SourceAlpha" result="shadowOffsetOuter1"/><feGaussianBlur stdDeviation="16" in="shadowOffsetOuter1" result="shadowBlurOuter1"/><feColorMatrix values="0 0 0 0 0.0862745098 0 0 0 0 0.0901960784 0 0 0 0 0.105882353 0 0 0 0.24 0" in="shadowBlurOuter1"/></filter><filter x="-466.7%" y="-250%" width="1033.3%" height="800%" filterUnits="objectBoundingBox" id="i"><feOffset dy="16" in="SourceAlpha" result="shadowOffsetOuter1"/><feGaussianBlur stdDeviation="16" in="shadowOffsetOuter1" result="shadowBlurOuter1"/><feColorMatrix values="0 0 0 0 0.062745098 0 0 0 0 0.0862745098 0 0 0 0 0.254901961 0 0 0 0.24 0" in="shadowBlurOuter1"/></filter><rect id="a" x="0" y="0" width="712" height="400" rx="2"/><rect id="b" x="0" y="0" width="712" height="400" rx="2"/><radialGradient cx="14.004%" cy="20.714%" fx="14.004%" fy="20.714%" r="204.167%" gradientTransform="matrix(.4898 .4898 -.1074 .34029 .094 .068)" id="c"><stop stop-color="#376DF9" offset="0%"/><stop stop-color="#FF5FA6" offset="61.018%"/><stop stop-color="#FFC55A" stop-opacity="0" offset="100%"/></radialGradient><circle id="g" cx="40" cy="40" r="40"/><path d="M48 40a.999.999 0 00-.427-.82l-10-7A1 1 0 0036 33v14a.999.999 0 001.573.82l10-7A.995.995 0 0048 40c0 .001 0 .001 0 0z" id="j"/></defs><g fill="none" fill-rule="evenodd"><use fill="#292B32" xlink:href="#a"/><mask id="d" fill="#fff"><use xlink:href="#b"/></mask><use fill="url(#c)" xlink:href="#b"/><g mask="url(#d)" stroke="url(#e)" stroke-width="1.5"><path d="M332.302 106c42.692 0 77.302 34.609 77.302 77.302 0 42.693-34.61 77.302-77.302 77.302-42.693 0-77.302-34.609-77.302-77.302C255 140.609 289.609 106 332.302 106z"/><path d="M336.986 109.306c42.692 0 77.302 34.609 77.302 77.302 0 42.693-34.61 77.302-77.302 77.302-42.693 0-77.302-34.61-77.302-77.302 0-42.693 34.61-77.302 77.302-77.302z"/><path d="M341.672 112.614c42.693 0 77.302 34.609 77.302 77.302 0 42.693-34.61 77.302-77.302 77.302-42.692 0-77.302-34.61-77.302-77.302 0-42.693 34.61-77.302 77.302-77.302z"/><path d="M346.356 115.92c42.693 0 77.302 34.609 77.302 77.302 0 42.693-34.61 77.302-77.302 77.302-42.692 0-77.302-34.61-77.302-77.302 0-42.693 34.61-77.302 77.302-77.302z"/><path d="M351.042 119.228c42.692 0 77.302 34.609 77.302 77.302 0 42.693-34.61 77.302-77.302 77.302-42.692 0-77.302-34.609-77.302-77.302 0-42.693 34.61-77.302 77.302-77.302z"/><path d="M355.726 122.534c42.693 0 77.302 34.609 77.302 77.302 0 42.693-34.61 77.302-77.302 77.302-42.693 0-77.302-34.61-77.302-77.302 0-42.693 34.609-77.302 77.302-77.302z"/><path d="M360.412 125.842c42.692 0 77.302 34.609 77.302 77.302 0 42.693-34.61 77.302-77.302 77.302-42.693 0-77.302-34.61-77.302-77.302 0-42.693 34.609-77.302 77.302-77.302z"/><path d="M365.096 129.148c42.693 0 77.302 34.609 77.302 77.302 0 42.693-34.609 77.302-77.302 77.302-42.693 0-77.302-34.609-77.302-77.302 0-42.693 34.609-77.302 77.302-77.302z"/><path d="M369.782 132.456c42.692 0 77.302 34.61 77.302 77.302 0 42.693-34.61 77.302-77.302 77.302-42.693 0-77.302-34.609-77.302-77.302 0-42.693 34.609-77.302 77.302-77.302z"/><path d="M374.466 135.762c42.693 0 77.302 34.609 77.302 77.302 0 42.693-34.609 77.302-77.302 77.302-42.693 0-77.302-34.61-77.302-77.302 0-42.693 34.61-77.302 77.302-77.302z"/><path d="M379.152 139.07c42.692 0 77.302 34.609 77.302 77.302 0 42.693-34.61 77.302-77.302 77.302-42.693 0-77.302-34.61-77.302-77.302 0-42.693 34.61-77.302 77.302-77.302z"/></g><g transform="translate(316 160)"><use fill="#000" filter="url(#f)" xlink:href="#g"/><use fill="url(#h)" xlink:href="#g"/></g><g transform="translate(316 160)"><use fill="#000" filter="url(#i)" xlink:href="#j"/><use fill="#6991FA" xlink:href="#j"/></g></g></svg>

Before

Width:  |  Height:  |  Size: 4.2 KiB

View File

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

View File

@ -1,42 +0,0 @@
// Generated by CoffeeScript 1.10.0
(function () {
var autoLink,
slice = [].slice;
autoLink = function () {
var callback, k, linkAttributes, option, options, pattern, v;
options = 1 <= arguments.length ? slice.call(arguments, 0) : [];
pattern = /(^|[\s\n]|<[A-Za-z]*\/?>)((?:https?|ftp):\/\/[\-A-Z0-9+\u0026\u2019@#\/%?=()~_|!:,.;]*[\-A-Z0-9+\u0026@#\/%=~()_|])/gi;
if (!(options.length > 0)) {
return this.replace(pattern, "$1<a target='_blank' href='$2'>$2</a>");
}
option = options[0];
callback = option["callback"];
linkAttributes = (function () {
var results;
results = [];
for (k in option) {
v = option[k];
if (k !== "callback") {
results.push(" " + k + "='" + v + "'");
}
}
return results;
})().join("");
return this.replace(pattern, function (match, space, url) {
var link;
link =
(typeof callback === "function" ? callback(url) : void 0) ||
"<a target='_blank' href='" +
url +
"'" +
linkAttributes +
">" +
url +
"</a>";
return "" + space + link;
});
};
String.prototype["autoLink"] = autoLink;
}.call(this));

View File

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

View File

@ -1,944 +0,0 @@
// Vars
var isMuted;
var videoIsPaused;
var dataChanel = null;
const browserName = getBrowserName();
const url = window.location.href;
const roomHash = url.substring(url.lastIndexOf("/") + 1).toLowerCase();
var mode = "camera";
// var isFullscreen = false;
var sendingCaptions = false;
var receivingCaptions = false;
const isWebRTCSupported =
navigator.getUserMedia ||
navigator.webkitGetUserMedia ||
navigator.mozGetUserMedia ||
navigator.msGetUserMedia ||
window.RTCPeerConnection;
// Element vars
const chatInput = document.querySelector(".compose input");
const remoteVideoVanilla = document.getElementById("remote-video");
const remoteVideo = $("#remote-video");
const captionText = $("#remote-video-text");
const localVideoText = $("#local-video-text");
const captionButtontext = $("#caption-button-text");
const entireChat = $("#entire-chat");
const chatZone = $("#chat-zone");
var VideoChat = {
connected: false,
willInitiateCall: false,
localICECandidates: [],
socket: io(),
remoteVideo: document.getElementById("remote-video"),
localVideo: document.getElementById("local-video"),
recognition: undefined,
// Call to getUserMedia (provided by adapter.js for cross browser compatibility)
// asking for access to both the video and audio streams. If the request is
// accepted callback to the onMediaStream function, otherwise callback to the
// noMediaStream function.
requestMediaStream: function (event) {
logIt("requestMediaStream");
rePositionLocalVideo();
navigator.mediaDevices
.getUserMedia({
video: true,
audio: true,
})
.then((stream) => {
VideoChat.onMediaStream(stream);
localVideoText.text("Drag Me");
setTimeout(() => localVideoText.fadeOut(), 5000);
})
.catch((error) => {
logIt(error);
logIt(
"Failed to get local webcam video, check webcam privacy settings"
);
// Keep trying to get user media
setTimeout(VideoChat.requestMediaStream, 1000);
});
},
// Called when a video stream is added to VideoChat
onMediaStream: function (stream) {
logIt("onMediaStream");
VideoChat.localStream = stream;
// Add the stream as video's srcObject.
// Now that we have webcam video sorted, prompt user to share URL
Snackbar.show({
text: "Here is the join link for your call: " + url,
actionText: "Copy Link",
width: "750px",
pos: "top-center",
actionTextColor: "#616161",
duration: 500000,
backgroundColor: "#16171a",
onActionClick: function (element) {
// Copy url to clipboard, this is achieved by creating a temporary element,
// adding the text we want to that element, selecting it, then deleting it
var copyContent = window.location.href;
$('<input id="some-element">')
.val(copyContent)
.appendTo("body")
.select();
document.execCommand("copy");
var toRemove = document.querySelector("#some-element");
toRemove.parentNode.removeChild(toRemove);
Snackbar.close();
},
});
VideoChat.localVideo.srcObject = stream;
// Now we're ready to join the chat room.
VideoChat.socket.emit("join", roomHash);
// Add listeners to the websocket
VideoChat.socket.on("full", chatRoomFull);
VideoChat.socket.on("offer", VideoChat.onOffer);
VideoChat.socket.on("ready", VideoChat.readyToCall);
VideoChat.socket.on(
"willInitiateCall",
() => (VideoChat.willInitiateCall = true)
);
},
// When we are ready to call, enable the Call button.
readyToCall: function (event) {
logIt("readyToCall");
// First to join call will most likely initiate call
if (VideoChat.willInitiateCall) {
logIt("Initiating call");
VideoChat.startCall();
}
},
// Set up a callback to run when we have the ephemeral token to use Twilio's TURN server.
startCall: function (event) {
logIt("startCall >>> Sending token request...");
VideoChat.socket.on("token", VideoChat.onToken(VideoChat.createOffer));
VideoChat.socket.emit("token", roomHash);
},
// When we receive the ephemeral token back from the server.
onToken: function (callback) {
logIt("onToken");
return function (token) {
logIt("<<< Received token");
// Set up a new RTCPeerConnection using the token's iceServers.
VideoChat.peerConnection = new RTCPeerConnection({
iceServers: token.iceServers,
});
// Add the local video stream to the peerConnection.
VideoChat.localStream.getTracks().forEach(function (track) {
VideoChat.peerConnection.addTrack(track, VideoChat.localStream);
});
// Add general purpose data channel to peer connection,
// used for text chats, captions, and toggling sending captions
dataChanel = VideoChat.peerConnection.createDataChannel("chat", {
negotiated: true,
// both peers must have same id
id: 0,
});
// Called when dataChannel is successfully opened
dataChanel.onopen = function (event) {
logIt("dataChannel opened");
};
// Handle different dataChannel types
dataChanel.onmessage = function (event) {
const receivedData = event.data;
// First 4 chars represent data type
const dataType = receivedData.substring(0, 4);
const cleanedMessage = receivedData.slice(4);
if (dataType === "mes:") {
handleRecieveMessage(cleanedMessage);
} else if (dataType === "cap:") {
recieveCaptions(cleanedMessage);
} else if (dataType === "tog:") {
toggleSendCaptions();
}
};
// Set up callbacks for the connection generating iceCandidates or
// receiving the remote media stream.
VideoChat.peerConnection.onicecandidate = VideoChat.onIceCandidate;
VideoChat.peerConnection.onaddstream = VideoChat.onAddStream;
// Set up listeners on the socket
VideoChat.socket.on("candidate", VideoChat.onCandidate);
VideoChat.socket.on("answer", VideoChat.onAnswer);
VideoChat.socket.on("requestToggleCaptions", () => toggleSendCaptions());
VideoChat.socket.on("recieveCaptions", (captions) =>
recieveCaptions(captions)
);
// Called when there is a change in connection state
VideoChat.peerConnection.oniceconnectionstatechange = function (event) {
switch (VideoChat.peerConnection.iceConnectionState) {
case "connected":
logIt("connected");
// Once connected we no longer have a need for the signaling server, so disconnect
VideoChat.socket.disconnect();
break;
case "disconnected":
logIt("disconnected");
case "failed":
logIt("failed");
// VideoChat.socket.connect
// VideoChat.createOffer();
// Refresh page if connection has failed
location.reload();
break;
case "closed":
logIt("closed");
break;
}
};
callback();
};
},
// When the peerConnection generates an ice candidate, send it over the socket to the peer.
onIceCandidate: function (event) {
logIt("onIceCandidate");
if (event.candidate) {
logIt(
`<<< Received local ICE candidate from STUN/TURN server (${event.candidate.address})`
);
if (VideoChat.connected) {
logIt(`>>> Sending local ICE candidate (${event.candidate.address})`);
VideoChat.socket.emit(
"candidate",
JSON.stringify(event.candidate),
roomHash
);
} else {
// 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.
// The peer may not have created the RTCPeerConnection yet, so we are waiting for the 'answer'
// to arrive. This will signal that the peer is ready to receive signaling.
VideoChat.localICECandidates.push(event.candidate);
}
}
},
// When receiving a candidate over the socket, turn it back into a real
// RTCIceCandidate and add it to the peerConnection.
onCandidate: function (candidate) {
// Update caption text
captionText.text("Found other user... connecting");
rtcCandidate = new RTCIceCandidate(JSON.parse(candidate));
logIt(
`onCandidate <<< Received remote ICE candidate (${rtcCandidate.address} - ${rtcCandidate.relatedAddress})`
);
VideoChat.peerConnection.addIceCandidate(rtcCandidate);
},
// Create an offer that contains the media capabilities of the browser.
createOffer: function () {
logIt("createOffer >>> Creating offer...");
VideoChat.peerConnection.createOffer(
function (offer) {
// If the offer is created successfully, set it as the local description
// and send it over the socket connection to initiate the peerConnection
// on the other side.
VideoChat.peerConnection.setLocalDescription(offer);
VideoChat.socket.emit("offer", JSON.stringify(offer), roomHash);
},
function (err) {
logIt("failed offer creation");
logIt(err, true);
}
);
},
// Create an answer with the media capabilities that both browsers share.
// This function is called with the offer from the originating browser, which
// needs to be parsed into an RTCSessionDescription and added as the remote
// description to the peerConnection object. Then the answer is created in the
// same manner as the offer and sent over the socket.
createAnswer: function (offer) {
logIt("createAnswer");
return function () {
logIt(">>> Creating answer...");
rtcOffer = new RTCSessionDescription(JSON.parse(offer));
VideoChat.peerConnection.setRemoteDescription(rtcOffer);
VideoChat.peerConnection.createAnswer(
function (answer) {
VideoChat.peerConnection.setLocalDescription(answer);
VideoChat.socket.emit("answer", JSON.stringify(answer), roomHash);
},
function (err) {
logIt("Failed answer creation.");
logIt(err, true);
}
);
};
},
// When a browser receives an offer, set up a callback to be run when the
// ephemeral token is returned from Twilio.
onOffer: function (offer) {
logIt("onOffer <<< Received offer");
VideoChat.socket.on(
"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.
onAnswer: function (answer) {
logIt("onAnswer <<< Received answer");
var rtcAnswer = new RTCSessionDescription(JSON.parse(answer));
// Set remote description of RTCSession
VideoChat.peerConnection.setRemoteDescription(rtcAnswer);
// The caller now knows that the callee is ready to accept new ICE candidates, so sending the buffer over
VideoChat.localICECandidates.forEach((candidate) => {
logIt(`>>> Sending local ICE candidate (${candidate.address})`);
// Send ice candidate over websocket
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
VideoChat.localICECandidates = [];
},
// Called when a stream is added to the peer connection
onAddStream: function (event) {
logIt("onAddStream <<< Received new stream from remote. Adding it...");
// Update remote video source
VideoChat.remoteVideo.srcObject = event.stream;
// Close the initial share url snackbar
Snackbar.close();
// Remove the loading gif from video
VideoChat.remoteVideo.style.background = "none";
// Update connection status
VideoChat.connected = true;
// Hide caption status text
captionText.fadeOut();
// Reposition local video after a second, as there is often a delay
// between adding a stream and the height of the video div changing
setTimeout(() => rePositionLocalVideo(), 500);
// var timesRun = 0;
// var interval = setInterval(function () {
// timesRun += 1;
// if (timesRun === 10) {
// clearInterval(interval);
// }
// rePositionLocalVideo();
// }, 300);
},
};
// Get name of browser session using user agent
function getBrowserName() {
var name = "Unknown";
if (window.navigator.userAgent.indexOf("MSIE") !== -1) {
} else if (window.navigator.userAgent.indexOf("Firefox") !== -1) {
name = "Firefox";
} else if (window.navigator.userAgent.indexOf("Opera") !== -1) {
name = "Opera";
} else if (window.navigator.userAgent.indexOf("Chrome") !== -1) {
name = "Chrome";
} else if (window.navigator.userAgent.indexOf("Safari") !== -1) {
name = "Safari";
}
return name;
}
// Basic logging class wrapper
function logIt(message, error) {
console.log(message);
}
// Called when socket receives message that room is full
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"
);
// Exit room and redirect
window.location.href = "/newcall";
}
// Reposition local video to top left of remote video
function rePositionLocalVideo() {
// Get position of remote video
var bounds = remoteVideo.position();
let localVideo = $("#local-video");
if (
/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(
navigator.userAgent
)
) {
bounds.top = $(window).height() * 0.7;
bounds.left += 10;
} else {
bounds.top += 10;
bounds.left += 10;
}
// Set position of local video
$("#moveable").css(bounds);
}
// Reposition captions to bottom of video
function rePositionCaptions() {
// Get remote video position
var bounds = remoteVideo.position();
bounds.top -= 10;
bounds.top = bounds.top + remoteVideo.height() - 1 * captionText.height();
// Reposition captions
captionText.css(bounds);
}
// Called when window is resized
function windowResized() {
rePositionLocalVideo();
rePositionCaptions();
}
// Fullscreen
// function openFullscreen() {
// try {
// // var elem = document.getElementById("remote-video");
// var elem = document.getElementById("body");
// if (!isFullscreen) {
// VideoChat.remoteVideo.classList.add("fullscreen");
// isFullscreen = true;
// if (elem.requestFullscreen) {
// elem.requestFullscreen();
// } else if (elem.mozRequestFullScreen) {
// /* Firefox */
// elem.mozRequestFullScreen();
// } else if (elem.webkitRequestFullscreen) {
// /* Chrome, Safari and Opera */
//
// elem.webkitRequestFullscreen();
// setTimeout(windowResized, 1000);
// } else if (elem.msRequestFullscreen) {
// /* IE/Edge */
// elem.msRequestFullscreen();
// }
// } else {
// isFullscreen = false;
// VideoChat.remoteVideo.classList.remove("fullscreen");
// if (document.exitFullscreen) {
// document.exitFullscreen();
// } else if (document.mozCancelFullScreen) {
// /* Firefox */
// document.mozCancelFullScreen();
// } else if (document.webkitExitFullscreen) {
// /* Chrome, Safari and Opera */
// document.webkitExitFullscreen();
// } else if (document.msExitFullscreen) {
// /* IE/Edge */
// document.msExitFullscreen();
// }
// }
// } catch (e) {
// logIt(e);
// }
// setTimeout(windowResized, 1000);
// }
// End Fullscreen
// Mute microphone
function muteMicrophone() {
var audioTrack = null;
// Get audio track to mute
VideoChat.peerConnection.getSenders().find(function (s) {
if (s.track.kind === "audio") {
audioTrack = s.track;
}
});
isMuted = !audioTrack.enabled;
audioTrack.enabled = isMuted;
isMuted = !isMuted;
// select mic button and mic button text
const micButtonIcon = document.getElementById("mic-icon");
const micButtonText = document.getElementById("mic-text");
// Update mute button text and icon
if (isMuted) {
micButtonIcon.classList.remove("fa-microphone");
micButtonIcon.classList.add("fa-microphone-slash");
micButtonText.innerText = "Unmute";
} else {
micButtonIcon.classList.add("fa-microphone");
micButtonIcon.classList.remove("fa-microphone-slash");
micButtonText.innerText = "Mute";
}
}
// End Mute microphone
// Pause Video
function pauseVideo() {
var videoTrack = null;
// Get video track to pause
VideoChat.peerConnection.getSenders().find(function (s) {
if (s.track.kind === "video") {
videoTrack = s.track;
}
});
videoIsPaused = !videoTrack.enabled;
videoTrack.enabled = videoIsPaused;
videoIsPaused = !videoIsPaused;
// select video button and video button text
const videoButtonIcon = document.getElementById("video-icon");
const videoButtonText = document.getElementById("video-text");
// update pause button icon and text
if (videoIsPaused) {
localVideoText.text("Video is paused");
localVideoText.show();
videoButtonIcon.classList.remove("fa-video");
videoButtonIcon.classList.add("fa-video-slash");
videoButtonText.innerText = "Unpause Video";
} else {
localVideoText.text("Video unpaused");
setTimeout(() => localVideoText.fadeOut(), 2000);
videoButtonIcon.classList.add("fa-video");
videoButtonIcon.classList.remove("fa-video-slash");
videoButtonText.innerText = "Pause Video";
}
}
// End pause Video
// Swap camera / screen share
function swap() {
// Handle swap video before video call is connected
if (!VideoChat.connected) {
alert("You must join a call before you can share your screen.");
return;
}
// Store swap button icon and text
const swapIcon = document.getElementById("swap-icon");
const swapText = document.getElementById("swap-text");
// If mode is camera then switch to screen share
if (mode === "camera") {
// Show accept screenshare snackbar
Snackbar.show({
text:
"Please allow screen share. Click the middle of the picture above and then press share.",
width: "400px",
pos: "bottom-center",
actionTextColor: "#616161",
duration: 50000,
});
// Request screen share, note we dont want to capture audio
// as we already have the stream from the Webcam
navigator.mediaDevices
.getDisplayMedia({
video: true,
audio: false,
})
.then(function (stream) {
// Close allow screenshare snackbar
Snackbar.close();
// Change display mode
mode = "screen";
// Update swap button icon and text
swapIcon.classList.remove("fa-desktop");
swapIcon.classList.add("fa-camera");
swapText.innerText = "Share Webcam";
switchStreamHelper(stream);
})
.catch(function (err) {
logIt(err);
logIt("Error sharing screen");
Snackbar.close();
});
// If mode is screenshare then switch to webcam
} else {
// Stop the screen share track
VideoChat.localVideo.srcObject.getTracks().forEach((track) => track.stop());
// Get webcam input
navigator.mediaDevices
.getUserMedia({
video: true,
audio: true,
})
.then(function (stream) {
// Change display mode
mode = "camera";
// Update swap button icon and text
swapIcon.classList.remove("fa-camera");
swapIcon.classList.add("fa-desktop");
swapText.innerText = "Share Screen";
switchStreamHelper(stream);
});
}
}
// Swap current video track with passed in stream
function switchStreamHelper(stream) {
// Get current video track
let videoTrack = stream.getVideoTracks()[0];
// Add listen for if the current track swaps, swap back
videoTrack.onended = function () {
swap();
};
if (VideoChat.connected) {
// Find sender
const sender = VideoChat.peerConnection.getSenders().find(function (s) {
// make sure tack types match
return s.track.kind === videoTrack.kind;
});
// Replace sender track
sender.replaceTrack(videoTrack);
}
// Update local video stream
VideoChat.localStream = videoTrack;
// Update local video object
VideoChat.localVideo.srcObject = stream;
// Unpause video on swap
if (videoIsPaused) {
pauseVideo();
}
}
// End swap camera / screen share
// Live caption
// Request captions from other user, toggles state
function requestToggleCaptions() {
// Handle requesting captions before connected
if (!VideoChat.connected) {
alert("You must be connected to a peer to use Live Caption");
return;
}
if (receivingCaptions) {
captionText.text("").fadeOut();
captionButtontext.text("Start Live Caption");
receivingCaptions = false;
} else {
Snackbar.show({
text:
"This is an experimental feature. Live caption requires the other user to be using Chrome",
width: "400px",
pos: "bottom-center",
actionTextColor: "#616161",
duration: 10000,
});
captionButtontext.text("End Live Caption");
receivingCaptions = true;
}
// Send request to get captions over data channel
dataChanel.send("tog:");
}
// Start/stop sending captions to other user
function toggleSendCaptions() {
if (sendingCaptions) {
sendingCaptions = false;
VideoChat.recognition.stop();
} else {
startSpeech();
sendingCaptions = true;
}
}
// Start speech recognition
function startSpeech() {
try {
var SpeechRecognition =
window.SpeechRecognition || window.webkitSpeechRecognition;
VideoChat.recognition = new SpeechRecognition();
// VideoChat.recognition.lang = "en";
} catch (e) {
sendingCaptions = false;
logIt(e);
logIt("error importing speech library");
// Alert other user that they cannon use live caption
dataChanel.send("cap:notusingchrome");
return;
}
// recognition.maxAlternatives = 3;
VideoChat.recognition.continuous = true;
// Show results that aren't final
VideoChat.recognition.interimResults = true;
var finalTranscript;
VideoChat.recognition.onresult = (event) => {
let interimTranscript = "";
for (let i = event.resultIndex, len = event.results.length; i < len; i++) {
var transcript = event.results[i][0].transcript;
if (event.results[i].isFinal) {
finalTranscript += transcript;
} else {
interimTranscript += transcript;
var charsToKeep = interimTranscript.length % 100;
// Send captions over data chanel,
// subtracting as many complete 100 char slices from start
dataChanel.send(
"cap:" +
interimTranscript.substring(interimTranscript.length - charsToKeep)
);
}
}
};
VideoChat.recognition.onend = function () {
logIt("on speech recording end");
// Restart speech recognition if user has not stopped it
if (sendingCaptions) {
startSpeech();
} else {
VideoChat.recognition.stop();
}
};
VideoChat.recognition.start();
}
// Recieve captions over datachannel
function recieveCaptions(captions) {
if (receivingCaptions) {
captionText.text("").fadeIn();
} else {
captionText.text("").fadeOut();
}
// Other user is not using chrome
if (captions === "notusingchrome") {
alert(
"Other caller must be using chrome for this feature to work. Live Caption turned off."
);
receivingCaptions = false;
captionText.text("").fadeOut();
captionButtontext.text("Start Live Caption");
return;
}
captionText.text(captions);
rePositionCaptions();
}
// End Live caption
// Translation
// function translate(text) {
// let fromLang = "en";
// let toLang = "zh";
// // let text = "hello how are you?";
// const API_KEY = "APIKEYHERE";
// let gurl = `https://translation.googleapis.com/language/translate/v2?key=${API_KEY}`;
// gurl += "&q=" + encodeURI(text);
// gurl += `&source=${fromLang}`;
// gurl += `&target=${toLang}`;
// fetch(gurl, {
// method: "GET",
// headers: {
// "Content-Type": "application/json",
// Accept: "application/json",
// },
// })
// .then((res) => res.json())
// .then((response) => {
// // console.log("response from google: ", response);
// // return response["data"]["translations"][0]["translatedText"];
// logIt(response);
// var translatedText =
// response["data"]["translations"][0]["translatedText"];
// console.log(translatedText);
// dataChanel.send("cap:" + translatedText);
// })
// .catch((error) => {
// console.log("There was an error with the translation request: ", error);
// });
// }
// End Translation
// Text Chat
// Add text message to chat screen on page
function addMessageToScreen(msg, isOwnMessage) {
if (isOwnMessage) {
$(".chat-messages").append(
'<div class="message-item customer cssanimation fadeInBottom"><div class="message-bloc"><div class="message">' +
msg +
"</div></div></div>"
);
} else {
$(".chat-messages").append(
'<div class="message-item moderator cssanimation fadeInBottom"><div class="message-bloc"><div class="message">' +
msg +
"</div></div></div>"
);
}
}
// Listen for enter press on chat input
chatInput.addEventListener("keypress", function (event) {
if (event.keyCode === 13) {
// Prevent page refresh on enter
event.preventDefault();
var msg = chatInput.value;
// Prevent cross site scripting
msg = msg.replace(/</g, "&lt;").replace(/>/g, "&gt;");
// Make links clickable
msg = msg.autoLink();
// Send message over data channel
dataChanel.send("mes:" + msg);
// Add message to screen
addMessageToScreen(msg, true);
// Auto scroll chat down
chatZone.scrollTop(chatZone[0].scrollHeight);
// Clear chat input
chatInput.value = "";
}
});
// Called when a message is recieved over the dataChannel
function handleRecieveMessage(msg) {
// Add message to screen
addMessageToScreen(msg, false);
// Auto scroll chat down
chatZone.scrollTop(chatZone[0].scrollHeight);
// Show chat if hidden
if (entireChat.is(":hidden")) {
toggleChat();
}
}
// Show and hide chat
function toggleChat() {
var chatIcon = document.getElementById("chat-icon");
var chatText = $("#chat-text");
if (entireChat.is(":visible")) {
entireChat.fadeOut();
// Update show chat buttton
chatText.text("Show Chat");
chatIcon.classList.remove("fa-comment-slash");
chatIcon.classList.add("fa-comment");
} else {
entireChat.fadeIn();
// Update show chat buttton
chatText.text("Hide Chat");
chatIcon.classList.remove("fa-comment");
chatIcon.classList.add("fa-comment-slash");
}
}
// End Text chat
//Picture in picture
function togglePictureInPicture() {
if (
"pictureInPictureEnabled" in document ||
remoteVideoVanilla.webkitSetPresentationMode
) {
if (document.pictureInPictureElement) {
document.exitPictureInPicture().catch((error) => {
logIt("Error exiting pip.");
logIt(error);
});
} else if (remoteVideoVanilla.webkitPresentationMode === "inline") {
remoteVideoVanilla.webkitSetPresentationMode("picture-in-picture");
} else if (
remoteVideoVanilla.webkitPresentationMode === "picture-in-picture"
) {
remoteVideoVanilla.webkitSetPresentationMode("inline");
} else {
remoteVideoVanilla.requestPictureInPicture().catch((error) => {
alert(
"You must be connected to another person to enter picture in picture."
);
});
}
} else {
alert(
"Picture in picture is not supported in your browser. Consider using Chrome or Safari."
);
}
}
//Picture in picture
function startUp() {
// Try and detect in-app browsers and redirect
var ua = navigator.userAgent || navigator.vendor || window.opera;
if (
DetectRTC.isMobileDevice &&
(ua.indexOf("FBAN") > -1 ||
ua.indexOf("FBAV") > -1 ||
ua.indexOf("Instagram") > -1)
) {
if (DetectRTC.osName === "iOS") {
window.location.href = "/notsupportedios";
} else {
window.location.href = "/notsupported";
}
}
// Redirect all iOS browsers that are not Safari
if (DetectRTC.isMobileDevice) {
if (DetectRTC.osName === "iOS" && !DetectRTC.browser.isSafari) {
window.location.href = "/notsupportedios";
}
}
if (!isWebRTCSupported || browserName === "MSIE") {
window.location.href = "/notsupported";
}
// Set tab title
document.title = "Zipcall - " + url.substring(url.lastIndexOf("/") + 1);
// get webcam on load
VideoChat.requestMediaStream();
// Captions hidden by default
captionText.text("").fadeOut();
// Make local video draggable
$("#moveable").draggable({ containment: "window" });
// Hide button labels on load
$(".HoverState").hide();
// Text chat hidden by default
entireChat.hide();
// Show hide button labels on hover
$(document).ready(function () {
$(".hoverButton").mouseover(function () {
$(".HoverState").hide();
$(this).next().show();
});
$(".hoverButton").mouseout(function () {
$(".HoverState").hide();
});
});
// Fade out / show UI on mouse move
var timedelay = 1;
function delayCheck() {
if (timedelay === 5) {
// $(".multi-button").fadeOut();
$("#header").fadeOut();
timedelay = 1;
}
timedelay = timedelay + 1;
}
$(document).mousemove(function () {
$(".multi-button").fadeIn();
$("#header").fadeIn();
$(".multi-button").style = "";
timedelay = 1;
clearInterval(_delay);
_delay = setInterval(delayCheck, 500);
});
_delay = setInterval(delayCheck, 500);
// Show accept webcam snackbar
Snackbar.show({
text: "Please allow microphone and webcam access",
actionText: "Show Me How",
width: "455px",
pos: "top-right",
actionTextColor: "#616161",
duration: 50000,
onActionClick: function (element) {
window.open(
"https://getacclaim.zendesk.com/hc/en-us/articles/360001547832-Setting-the-default-camera-on-your-browser",
"_blank"
);
},
});
// Set caption text on start
captionText.text("Waiting for other user to join...").fadeIn();
// Reposition captions on start
rePositionCaptions();
// On change media devices refresh page and switch to system default
navigator.mediaDevices.ondevicechange = () => window.location.reload();
}
startUp();

View File

@ -1,174 +0,0 @@
/*!
* jQuery UI Touch Punch 0.2.3
*
* Copyright 20112014, Dave Furfero
* Dual licensed under the MIT or GPL Version 2 licenses.
*
* Depends:
* jquery.ui.widget.js
* jquery.ui.mouse.js
*/
(function ($) {
// Detect touch support
$.support.touch = "ontouchend" in document;
// Ignore browsers without touch support
if (!$.support.touch) {
return;
}
var mouseProto = $.ui.mouse.prototype,
_mouseInit = mouseProto._mouseInit,
_mouseDestroy = mouseProto._mouseDestroy,
touchHandled;
/**
* Simulate a mouse event based on a corresponding touch event
* @param {Object} event A touch event
* @param {String} simulatedType The corresponding mouse event
*/
function simulateMouseEvent(event, simulatedType) {
// Ignore multi-touch events
if (event.originalEvent.touches.length > 1) {
return;
}
event.preventDefault();
var touch = event.originalEvent.changedTouches[0],
simulatedEvent = document.createEvent("MouseEvents");
// Initialize the simulated mouse event using the touch event's coordinates
simulatedEvent.initMouseEvent(
simulatedType, // type
true, // bubbles
true, // cancelable
window, // view
1, // detail
touch.screenX, // screenX
touch.screenY, // screenY
touch.clientX, // clientX
touch.clientY, // clientY
false, // ctrlKey
false, // altKey
false, // shiftKey
false, // metaKey
0, // button
null // relatedTarget
);
// Dispatch the simulated event to the target element
event.target.dispatchEvent(simulatedEvent);
}
/**
* Handle the jQuery UI widget's touchstart events
* @param {Object} event The widget element's touchstart event
*/
mouseProto._touchStart = function (event) {
var self = this;
// Ignore the event if another widget is already being handled
if (
touchHandled ||
!self._mouseCapture(event.originalEvent.changedTouches[0])
) {
return;
}
// Set the flag to prevent other widgets from inheriting the touch event
touchHandled = true;
// Track movement to determine if interaction was a click
self._touchMoved = false;
// Simulate the mouseover event
simulateMouseEvent(event, "mouseover");
// Simulate the mousemove event
simulateMouseEvent(event, "mousemove");
// Simulate the mousedown event
simulateMouseEvent(event, "mousedown");
};
/**
* Handle the jQuery UI widget's touchmove events
* @param {Object} event The document's touchmove event
*/
mouseProto._touchMove = function (event) {
// Ignore event if not handled
if (!touchHandled) {
return;
}
// Interaction was not a click
this._touchMoved = true;
// Simulate the mousemove event
simulateMouseEvent(event, "mousemove");
};
/**
* Handle the jQuery UI widget's touchend events
* @param {Object} event The document's touchend event
*/
mouseProto._touchEnd = function (event) {
// Ignore event if not handled
if (!touchHandled) {
return;
}
// Simulate the mouseup event
simulateMouseEvent(event, "mouseup");
// Simulate the mouseout event
simulateMouseEvent(event, "mouseout");
// If the touch interaction did not move, it should trigger a click
if (!this._touchMoved) {
// Simulate the click event
simulateMouseEvent(event, "click");
}
// Unset the flag to allow other widgets to inherit the touch event
touchHandled = false;
};
/**
* A duck punch of the $.ui.mouse _mouseInit method to support touch events.
* This method extends the widget with bound touch event handlers that
* translate touch events to mouse events and pass them to the widget's
* original mouse event handling methods.
*/
mouseProto._mouseInit = function () {
var self = this;
// Delegate the touch handlers to the widget's element
self.element.bind({
touchstart: $.proxy(self, "_touchStart"),
touchmove: $.proxy(self, "_touchMove"),
touchend: $.proxy(self, "_touchEnd"),
});
// Call the original $.ui.mouse init method
_mouseInit.call(self);
};
/**
* Remove the touch event handlers
*/
mouseProto._mouseDestroy = function () {
var self = this;
// Delegate the touch handlers to the widget's element
self.element.unbind({
touchstart: $.proxy(self, "_touchStart"),
touchmove: $.proxy(self, "_touchMove"),
touchend: $.proxy(self, "_touchEnd"),
});
// Call the original $.ui.mouse destroy method
_mouseDestroy.call(self);
};
})(jQuery);

View File

@ -1,340 +0,0 @@
!(function () {
"use strict";
const e = document.getElementsByClassName("accordion-header");
function t(e, t) {
e.classList.add("is-active"), (t.style.maxHeight = t.scrollHeight + "px");
}
function n(e, t) {
e.classList.remove("is-active"), (t.style.maxHeight = null);
}
if (e.length > 0)
for (let i = 0; i < e.length; i++) {
const s = e[i],
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 () {
"use strict";
let e = {
touchStartX: 0,
touchEndX: 0,
minSwipePixels: 30,
detectionZone: void 0,
swipeCallback: function () {},
init: function (t, n) {
(e.swipeCallback = n),
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;
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);
},
swipe: function (t, n) {
let i = {};
(i.direction = t), (i.movedPixels = n), e.swipeCallback(i);
},
};
const t = document.getElementsByClassName("carousel-items");
function n(e, t) {
void 0 === t && (t = "next");
let n = e.getElementsByClassName("carousel-item is-active")[0],
i = "next" === t ? n.nextElementSibling : n.previousElementSibling,
s = n.getAttribute("data-carousel"),
a = e.parentNode.getElementsByClassName("carousel-bullet")[s],
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"));
}
function i(e, t) {
let n,
i = 0;
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) {
e && clearInterval(e);
}
if (t.length > 0)
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");
(d.className = "carousel-bullets"),
l.parentNode.insertBefore(d, l.nextSibling);
for (let e = 0; e < c.length; e++) {
c[e].setAttribute("data-carousel", e),
c[e].classList.contains("is-active") && (o = e);
let t = document.createElement("button");
(t.className = "carousel-bullet"),
t.setAttribute("data-bullet", e),
l.parentNode
.getElementsByClassName("carousel-bullets")[0]
.appendChild(t);
}
c[o].classList.add("is-active");
let u = l.parentNode.getElementsByClassName("carousel-bullet");
u[o].classList.add("is-active"),
i(0, c),
window.addEventListener("resize", function () {
i(0, c);
});
let m = !1;
r &&
(m = setInterval(function () {
n(l, "next");
}, r));
for (let e = 0; e < u.length; e++) {
let t = u[e];
t.addEventListener("click", function (e) {
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 < c.length; e++)
c[e].classList.remove("is-active");
let n = this.getAttribute("data-bullet");
c[n].classList.add("is-active"),
this.classList.add("is-active"),
s(m);
});
}
e.init(l, function (e) {
"left" === e.direction
? n(l, "next")
: "right" === e.direction && n(l, "prev"),
s(m);
});
}
})(),
(function () {
"use strict";
document.documentElement.classList.remove("no-js"),
document.documentElement.classList.add("js"),
window.addEventListener("load", function () {
document.body.classList.add("is-loaded");
});
})(),
(function () {
"use strict";
const e = document.getElementById("header-nav-toggle"),
t = document.getElementById("header-nav");
e &&
(e.addEventListener("click", function () {
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");
}),
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";
const e = document.getElementsByClassName("modal"),
t = document.getElementsByClassName("modal-trigger");
function n() {
document.body.classList.remove("modal-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++) {
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;
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) {
(e.target.classList.contains("modal") ||
e.target.classList.contains("modal-close-trigger")) &&
(e.preventDefault(), n());
}),
document.addEventListener("keydown", function (e) {
27 === (e || window.event).keyCode && n();
});
})(),
(function () {
"use strict";
const e = document.getElementById("pricing-toggle");
function t() {
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");
}
e && (window.addEventListener("load", t), e.addEventListener("change", t));
})(),
(function () {
"use strict";
const e = document.querySelectorAll("[class*=reveal-]");
let t = window.innerHeight;
function n(e, t) {
var n = 0;
return function () {
var i = new Date().getTime();
if (!(i - n < e)) return (n = i), t.apply(void 0, arguments);
};
}
function i() {
for (let i = 0; i < e.length; i++) {
let s = e[i],
a = s.getAttribute("data-reveal-delay"),
l = s.getAttribute("data-reveal-offset")
? s.getAttribute("data-reveal-offset")
: "200",
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;
!(function () {
if (
e.length >
document.querySelectorAll("[class*=reveal-].is-revealed").length
)
return;
window.removeEventListener("load", i),
window.removeEventListener("scroll", s),
window.removeEventListener("resize", a);
})();
}
function s() {
n(30, i());
}
function a() {
(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));
})(),
(function () {
"use strict";
const e = document.getElementsByClassName("smooth-scroll"),
t = (e, n, i, s, a) => {
const l = n - e;
let c = l / i;
const o = (function (e) {
return e < 0.5 ? 2 * e * e : (4 - 2 * e) * e - 1;
})((c = Math.min(c, 1)));
window.scroll(0, a + s * o),
l < i &&
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++) {
e[n].addEventListener("click", function (e) {
e.preventDefault();
const n = e.target.closest(".smooth-scroll"),
i = n.href.split("#")[1],
s = document.getElementById(i),
a = n.getAttribute("data-duration") || 1e3;
s &&
window.requestAnimationFrame((e) => {
const n = e || new Date().getTime(),
i = n,
l = window.pageYOffset,
c = s.getBoundingClientRect().top;
t(i, n, a, c, l);
});
});
}
})();

View File

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

View File

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

View File

@ -1,124 +0,0 @@
var adjectives = [
"small",
"big",
"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",
"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 noun = nouns[Math.floor(Math.random() * nouns.length)];
noun = noun.charAt(0).toUpperCase() + noun.substring(1);
adjective = adjective.charAt(0).toUpperCase() + adjective.substring(1);
document.getElementById("input-01").value = adjective + noun;

View File

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

View File

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

View File

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

View File

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

View File

@ -1,393 +0,0 @@
<!DOCTYPE html>
<html lang="en" class="no-js">
<head>
<!-- Global site tag (gtag.js) - Google Analytics -->
<script
async
src="https://www.googletagmanager.com/gtag/js?id=UA-162048272-1"
></script>
<script>
window.dataLayer = window.dataLayer || [];
function gtag() {
dataLayer.push(arguments);
}
gtag("js", new Date());
gtag("config", "UA-162048272-1");
</script>
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width,initial-scale=1" />
<title>Zipcall</title>
<link rel="stylesheet" href="css/landing.css" />
<link rel="shortcut icon" href="images/logo.svg" />
<meta property="og:title" content="Zipcall - Decentralized video calls" />
<meta
property="og:description"
content="Decentralized video
calling provides real-time HD quality and latency simply
not available with traditional technology."
/>
<meta property="og:image" content="https://zipcall.io/images/preview.png" />
<meta property="og:url" content="https://zipcall.io/" />
</head>
<body class="has-animations">
<div class="body-wrap">
<header class="site-header reveal-from-top">
<div class="container">
<div class="site-header-inner">
<div class="brand">
<h1 class="m-0">
<a href="/"
><img src="images/logo.svg" alt="Neon" width="32" height="32"
/></a>
</h1>
</div>
</div>
</div>
</header>
<main class="site-content">
<section class="hero section illustration-section-01">
<div class="container">
<div class="hero-inner section-inner">
<div class="split-wrap invert-mobile">
<div class="split-item">
<div
class="hero-content split-item-content center-content-mobile"
>
<h1
class="mt-0 mb-16 reveal-from-bottom"
data-reveal-delay="150"
>
Zipcall.io<br />Free browser based video calling for
everyone.
</h1>
<p
class="mt-0 mb-32 reveal-from-bottom"
data-reveal-delay="300"
>
Simple, Secure, and Fast. Peer to peer 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"
style="
border: 0;
background: linear-gradient(
100deg,
#376df9 0,
#ff5fa0 75%,
#ffc55a 100%
);
"
href="/newcall"
>Try now</a
>
</div>
</div>
<style>
@media (min-width: 641px) {
.hero .split-wrap .split-item {
min-height: 492px;
}
}
</style>
</div>
</div>
</div>
</div>
</section>
<section class="features-tiles section center-content">
<div class="container">
<div class="features-tiles-inner section-inner has-top-divider">
<div class="section-header">
<div
class="container-xs reveal-from-bottom"
data-reveal-delay="650"
>
<h2 class="mt-0 mb-16">See the whole picture</h2>
<p class="m-0">
Zipcall is built radically different. We left behind slow
bulky servers, opting for decentralized peer to peer
calling. We engineered a platform with maximum video quality
and lowest latency.
</p>
</div>
</div>
<div class="tiles-wrap">
<div class="tiles-item reveal-from-right">
<div class="tiles-item-inner">
<div class="features-tiles-item-header">
<div class="features-tiles-item-image mb-16">
<img
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 video compression combined with our
scaling optimization makes your calls crystal clear.
</p>
</div>
</div>
</div>
<div class="tiles-item reveal-from-left">
<div class="tiles-item-inner">
<div class="features-tiles-item-header">
<div class="features-tiles-item-image mb-16">
<img
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 downloads. No plugins. No nonsense. Just open Zipcall
in your browser and get back to what matters most.
</p>
</div>
</div>
</div>
<div class="tiles-item reveal-from-right">
<div class="tiles-item-inner">
<div class="features-tiles-item-header">
<div class="features-tiles-item-image mb-16">
<img
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>
<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 class="tiles-item reveal-from-left">
<div class="tiles-item-inner">
<div class="features-tiles-item-header">
<div class="features-tiles-item-image mb-16">
<img
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 is single use, data stays between you and your
caller. Zipcall is built privacy first.
</p>
</div>
</div>
</div>
<div class="tiles-item reveal-from-right">
<div class="tiles-item-inner">
<div class="features-tiles-item-header">
<div class="features-tiles-item-image mb-16">
<img
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>
<p class="m-0 text-sm">
Calls are entirely between you and your caller,
decentralized from any server. Call data never leaves
the browser. Cool right?
</p>
</div>
</div>
</div>
<div class="tiles-item reveal-from-left">
<div class="tiles-item-inner">
<div class="features-tiles-item-header">
<div class="features-tiles-item-image mb-16">
<img
src="images/feature-tile-icon-06.svg"
alt="Feature tile icon 06"
width="72"
height="72"
/>
</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>
</section>
<section class="team section center-content">
<div class="container">
<div class="team-inner section-inner has-top-divider">
<div class="section-header center-content reveal-from-bottom">
<div class="container-xs">
<h2 class="mt-0 mb-16">
Meet the team
</h2>
<!-- <p class="m-0">-->
<!-- One man show... for now-->
<!-- </p>-->
</div>
</div>
<div class="tiles-wrap">
<div class="tiles-item reveal-from-bottom">
<div class="tiles-item-inner">
<div class="team-item-header">
<div class="team-item-image mb-24">
<img
src="images/portrait.png"
alt="Team member 01"
width="180"
height="180"
/>
</div>
</div>
<div class="team-item-content">
<a target="_blank" href="https://ianramzy.com">
<h5 class="team-item-name mt-0 mb-4">Ian Ramzy</h5>
</a>
<div
class="team-item-role text-xxs fw-500 tt-u text-color-primary mb-8"
>
Software Engineer
</div>
<p class="m-0 text-sm">
Connecting the world together one Zipcall at a time.
</p>
</div>
</div>
</div>
</div>
</div>
</div>
</section>
<section class="section">
<div class="container">
<div class="section-inner has-top-divider">
<div class="container-xs">
<div class="section-header center-content">
<h2 class="m-0">
Try an easier, more secure way of calling.
</h2>
</div>
<div class="center-content">
<a
class="button button-primary button-wide-mobile pulse"
style="
border: 0;
background: linear-gradient(
100deg,
#376df9 0,
#ff5fa0 75%,
#ffc55a 100%
);
"
href="/newcall"
>Try now</a
>
</div>
</div>
</div>
</div>
</section>
</main>
<footer class="site-footer center-content-mobile">
<div class="container">
<div class="site-footer-inner">
<div class="footer-top space-between text-xxs">
<div class="brand">
<a href="/"
><img src="images/logo.svg" alt="Neon" width="32" height="32"
/></a>
</div>
<div class="footer-social">
<div>
<a
target="_blank"
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>
<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>
</a>
</div>
</div>
</div>
<div
class="footer-bottom space-between text-xxs invert-order-desktop"
>
<nav class="footer-nav">
<ul class="list-reset">
<li>
<a target="_blank" href="https://ianramzy.com"
>Made with ❤️ by Ian Ramzy</a
>
</li>
<!-- <li><a href="#">Contact</a></li>-->
<!-- <li><a href="#">About us</a></li>-->
<!-- <li><a href="#">FAQ's</a></li>-->
<!-- <li><a href="#">Support</a></li>-->
</ul>
</nav>
<div class="footer-copyright">
&copy; 2020 Zipcall, all rights reserved
</div>
</div>
</div>
</div>
</footer>
</div>
<script src="js/landing.js"></script>
</body>
</html>

View File

@ -1,180 +0,0 @@
<!DOCTYPE html>
<html lang="en" class="no-js">
<head>
<!-- Global site tag (gtag.js) - Google Analytics -->
<script
async
src="https://www.googletagmanager.com/gtag/js?id=UA-162048272-1"
></script>
<script>
window.dataLayer = window.dataLayer || [];
function gtag() {
dataLayer.push(arguments);
}
gtag("js", new Date());
gtag("config", "UA-162048272-1");
</script>
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width,initial-scale=1" />
<title>Zipcall</title>
<link rel="stylesheet" href="css/landing.css" />
<link rel="stylesheet" href="css/newcall.css" />
<link rel="shortcut icon" href="images/logo.svg" />
<meta property="og:title" content="Zipcall - Decentralized video calls" />
<meta
property="og:description"
content="Decentralized video
calling provides real-time HD quality and latency simply
not available with traditional technology."
/>
<meta property="og:image" content="https://zipcall.io/images/preview.png" />
<meta property="og:url" content="https://zipcall.io/" />
</head>
<body class="has-animations">
<div class="body-wrap">
<header class="site-header reveal-from-top">
<div class="container">
<div class="site-header-inner">
<div class="brand">
<h1 class="m-0">
<a href="/"
><img src="images/logo.svg" alt="Neon" width="32" height="32"
/></a>
</h1>
</div>
</div>
</div>
</header>
<main class="site-content">
<section class="hero section illustration-section-01">
<div class="container">
<div class="hero-inner section-inner">
<div class="split-wrap invert-mobile">
<div class="split-item">
<div
class="hero-content split-item-content center-content-mobile"
>
<h1
class="mt-0 mb-16 reveal-from-bottom"
data-reveal-delay="150"
>
Pick name. <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 pick a call
name and share your custom link. It's really that easy.
</p>
</div>
<style>
@media (min-width: 641px) {
.hero .split-wrap .split-item {
min-height: 492px;
}
}
</style>
</div>
</div>
</div>
</div>
</section>
<section class="cta section center-content-mobile reveal-from-bottom">
<div class="container">
<div class="cta-inner section-inner cta-split">
<div class="cta-slogan">
<h3 class="m-0">
Pick a call name.<br />
How about this one?
</h3>
</div>
<div class="cta-action">
<div class="mb-24">
<label class="form-label screen-reader" for="input-01"
>This is a label</label
>
<div class="form-group-desktop">
<input
class="form-input"
type="text"
id="input-01"
value="PurpleSquid"
/>
<button
class="button button-primary pulse"
onclick="{window.location.href = '/join/' + document.getElementById('input-01').value}"
>
Go To My Call
</button>
</div>
</div>
</div>
</div>
</div>
</section>
</main>
<footer class="site-footer center-content-mobile">
<div class="container">
<div class="site-footer-inner">
<div class="footer-top space-between text-xxs">
<div class="brand">
<a href="/"
><img src="images/logo.svg" alt="Neon" width="32" height="32"
/></a>
</div>
<div class="footer-social">
<div>
<a
target="_blank"
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>
<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>
</a>
</div>
</div>
</div>
<div
class="footer-bottom space-between text-xxs invert-order-desktop"
>
<nav class="footer-nav">
<ul class="list-reset">
<li>
<a target="_blank" href="https://ianramzy.com"
>Made with ❤️ by Ian Ramzy</a
>
</li>
<!-- <li><a href="#">Contact</a></li>-->
<!-- <li><a href="#">About us</a></li>-->
<!-- <li><a href="#">FAQ's</a></li>-->
<!-- <li><a href="#">Support</a></li>-->
</ul>
</nav>
<div class="footer-copyright">
&copy; 2020 Zipcall, all rights reserved
</div>
</div>
</div>
</div>
</footer>
</div>
<script src="js/landing.js"></script>
<script src="js/newroom.js"></script>
</body>
</html>

View File

@ -1,136 +0,0 @@
<!DOCTYPE html>
<html lang="en" class="no-js">
<head>
<!-- Global site tag (gtag.js) - Google Analytics -->
<script
async
src="https://www.googletagmanager.com/gtag/js?id=UA-162048272-1"
></script>
<script>
window.dataLayer = window.dataLayer || [];
function gtag() {
dataLayer.push(arguments);
}
gtag("js", new Date());
gtag("config", "UA-162048272-1");
</script>
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width,initial-scale=1" />
<title>Zipcall</title>
<link rel="stylesheet" href="css/landing.css" />
<link rel="shortcut icon" href="images/logo.svg" />
<meta property="og:title" content="Zipcall - Decentralized video calls" />
<meta
property="og:description"
content="Decentralized video
calling provides real-time HD quality and latency simply
not available with traditional technology."
/>
<meta property="og:image" content="https://zipcall.io/images/preview.png" />
<meta property="og:url" content="https://zipcall.io/" />
</head>
<body class="has-animations">
<div class="body-wrap">
<header class="site-header reveal-from-top">
<div class="container">
<div class="site-header-inner">
<div class="brand">
<h1 class="m-0">
<a href="/"
><img src="images/logo.svg" alt="Neon" width="32" height="32"
/></a>
</h1>
</div>
</div>
</div>
</header>
<main class="site-content">
<section class="hero section illustration-section-01">
<div class="container">
<div class="hero-inner section-inner">
<div class="split-wrap invert-mobile">
<div class="split-item">
<div
class="hero-content split-item-content center-content-mobile"
>
<h1
class="mt-0 mb-16 reveal-from-bottom"
data-reveal-delay="150"
>
Your browser is not supported. Try updating your browser
or try Chrome, Safari, or Firefox.
</h1>
</div>
<style>
@media (min-width: 641px) {
.hero .split-wrap .split-item {
min-height: 492px;
}
}
</style>
</div>
</div>
</div>
</div>
</section>
</main>
<footer class="site-footer center-content-mobile">
<div class="container">
<div class="site-footer-inner">
<div class="footer-top space-between text-xxs">
<div class="brand">
<a href="/"
><img src="images/logo.svg" alt="Neon" width="32" height="32"
/></a>
</div>
<div class="footer-social">
<div>
<a
target="_blank"
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>
<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>
</a>
</div>
</div>
</div>
<div
class="footer-bottom space-between text-xxs invert-order-desktop"
>
<nav class="footer-nav">
<ul class="list-reset">
<li>
<a target="_blank" href="https://ianramzy.com"
>Made with ❤️ by Ian Ramzy</a
>
</li>
<!-- <li><a href="#">Contact</a></li>-->
<!-- <li><a href="#">About us</a></li>-->
<!-- <li><a href="#">FAQ's</a></li>-->
<!-- <li><a href="#">Support</a></li>-->
</ul>
</nav>
<div class="footer-copyright">
&copy; 2020 Zipcall, all rights reserved
</div>
</div>
</div>
</div>
</footer>
</div>
<script src="js/landing.js"></script>
</body>
</html>

View File

@ -1,136 +0,0 @@
<!DOCTYPE html>
<html lang="en" class="no-js">
<head>
<!-- Global site tag (gtag.js) - Google Analytics -->
<script
async
src="https://www.googletagmanager.com/gtag/js?id=UA-162048272-1"
></script>
<script>
window.dataLayer = window.dataLayer || [];
function gtag() {
dataLayer.push(arguments);
}
gtag("js", new Date());
gtag("config", "UA-162048272-1");
</script>
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width,initial-scale=1" />
<title>Zipcall</title>
<link rel="stylesheet" href="css/landing.css" />
<link rel="shortcut icon" href="images/logo.svg" />
<meta property="og:title" content="Zipcall - Decentralized video calls" />
<meta
property="og:description"
content="Decentralized video
calling provides real-time HD quality and latency simply
not available with traditional technology."
/>
<meta property="og:image" content="https://zipcall.io/images/preview.png" />
<meta property="og:url" content="https://zipcall.io/" />
</head>
<body class="has-animations">
<div class="body-wrap">
<header class="site-header reveal-from-top">
<div class="container">
<div class="site-header-inner">
<div class="brand">
<h1 class="m-0">
<a href="/"
><img src="images/logo.svg" alt="Neon" width="32" height="32"
/></a>
</h1>
</div>
</div>
</div>
</header>
<main class="site-content">
<section class="hero section illustration-section-01">
<div class="container">
<div class="hero-inner section-inner">
<div class="split-wrap invert-mobile">
<div class="split-item">
<div
class="hero-content split-item-content center-content-mobile"
>
<h1
class="mt-0 mb-16 reveal-from-bottom"
data-reveal-delay="150"
>
Your browser is unsupported. Please open Zipcall in the
Safari app.
</h1>
</div>
<style>
@media (min-width: 641px) {
.hero .split-wrap .split-item {
min-height: 492px;
}
}
</style>
</div>
</div>
</div>
</div>
</section>
</main>
<footer class="site-footer center-content-mobile">
<div class="container">
<div class="site-footer-inner">
<div class="footer-top space-between text-xxs">
<div class="brand">
<a href="/"
><img src="images/logo.svg" alt="Neon" width="32" height="32"
/></a>
</div>
<div class="footer-social">
<div>
<a
target="_blank"
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>
<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>
</a>
</div>
</div>
</div>
<div
class="footer-bottom space-between text-xxs invert-order-desktop"
>
<nav class="footer-nav">
<ul class="list-reset">
<li>
<a target="_blank" href="https://ianramzy.com"
>Made with ❤️ by Ian Ramzy</a
>
</li>
<!-- <li><a href="#">Contact</a></li>-->
<!-- <li><a href="#">About us</a></li>-->
<!-- <li><a href="#">FAQ's</a></li>-->
<!-- <li><a href="#">Support</a></li>-->
</ul>
</nav>
<div class="footer-copyright">
&copy; 2020 Zipcall, all rights reserved
</div>
</div>
</div>
</div>
</footer>
</div>
<script src="js/landing.js"></script>
</body>
</html>

File diff suppressed because it is too large Load Diff

132
server.js
View File

@ -1,132 +0,0 @@
require("dotenv").config();
var sslRedirect = require("heroku-ssl-redirect");
// Get twillio auth and SID from heroku if deployed, else get from local .env file
var twillioAuthToken =
process.env.HEROKU_AUTH_TOKEN || process.env.LOCAL_AUTH_TOKEN;
var twillioAccountSID =
process.env.HEROKU_TWILLIO_SID || process.env.LOCAL_TWILLIO_SID;
var twilio = require("twilio")(twillioAccountSID, twillioAuthToken);
var express = require("express");
var app = express();
var http = require("http").createServer(app);
var io = require("socket.io")(http);
var path = require("path");
var public = path.join(__dirname, "public");
const url = require("url");
// enable ssl redirect
app.use(sslRedirect());
// Remove trailing slashes in url
app.use(function (req, res, next) {
if (req.path.substr(-1) === "/" && req.path.length > 1) {
let query = req.url.slice(req.path.length);
res.redirect(301, req.path.slice(0, -1) + query);
} else {
next();
}
});
app.get("/", function (req, res) {
res.sendFile(path.join(public, "landing.html"));
});
app.get("/newcall", function (req, res) {
res.sendFile(path.join(public, "newcall.html"));
});
app.get("/join/", function (req, res) {
res.redirect("/");
});
app.get("/join/*", function (req, res) {
if (Object.keys(req.query).length > 0) {
logIt("redirect:" + req.url + " to " + url.parse(req.url).pathname);
res.redirect(url.parse(req.url).pathname);
} else {
res.sendFile(path.join(public, "chat.html"));
}
});
app.get("/notsupported", function (req, res) {
res.sendFile(path.join(public, "notsupported.html"));
});
app.get("/notsupportedios", function (req, res) {
res.sendFile(path.join(public, "notsupportedios.html"));
});
// Serve static files in the public directory
app.use(express.static("public"));
// Simple logging function to add room name
function logIt(msg, room) {
if (room) {
console.log(room + ": " + msg);
} else {
console.log(msg);
}
}
// When a socket connects, set up the specific listeners we will use.
io.on("connection", function (socket) {
// When a client tries to join a room, only allow them if they are first or
// second in the room. Otherwise it is full.
socket.on("join", function (room) {
logIt("A client joined the room", room);
var clients = io.sockets.adapter.rooms[room];
var numClients = typeof clients !== "undefined" ? clients.length : 0;
if (numClients === 0) {
socket.join(room);
} else if (numClients === 1) {
socket.join(room);
// When the client is second to join the room, both clients are ready.
logIt("Broadcasting ready message", room);
// First to join call initiates call
socket.broadcast.to(room).emit("willInitiateCall", room);
socket.emit("ready", room).to(room);
socket.broadcast.to(room).emit("ready", room);
} else {
logIt("room already full", room);
socket.emit("full", room);
}
});
// When receiving the token message, use the Twilio REST API to request an
// token to get ephemeral credentials to use the TURN server.
socket.on("token", function (room) {
logIt("Received token request", room);
twilio.tokens.create(function (err, response) {
if (err) {
logIt(err, room);
} else {
logIt("Token generated. Returning it to the browser client", room);
socket.emit("token", response).to(room);
}
});
});
// Relay candidate messages
socket.on("candidate", function (candidate, room) {
logIt("Received candidate. Broadcasting...", room);
socket.broadcast.to(room).emit("candidate", candidate);
});
// Relay offers
socket.on("offer", function (offer, room) {
logIt("Received offer. Broadcasting...", room);
socket.broadcast.to(room).emit("offer", offer);
});
// Relay answers
socket.on("answer", function (answer, room) {
logIt("Received answer. Broadcasting...", room);
socket.broadcast.to(room).emit("answer", answer);
});
});
// Listen for Heroku port, otherwise just use 3000
var port = process.env.PORT || 3000;
http.listen(port, function () {
console.log("http://localhost:" + port);
});