A Pen by Alessandro Falchi on CodePen.
Created
May 18, 2016 17:13
-
-
Save afalchi82/34b8354f360f0d7e5bb82866c823fc5c to your computer and use it in GitHub Desktop.
Vocal chatroom (WIP)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
section#angular-app | |
.container | |
.row | |
.col-xs-12 | |
h1 Vocal Chatroom <i class="fa fa-microphone" aria-hidden="true"></i> | |
small speak in your browser's voice (<strong>turn on the volume <i class="fa fa-smile-o" aria-hidden="true"></i></strong>) | |
// h4 CHAT ID: | |
strong {{chat_id}} | |
// | |
.row | |
.col-xs-12 | |
| Chats: {{chats.length}} <br> | |
| ChatID: {{user.chatroom}} | |
br | |
pre | Auth: {{authObj | json}} | |
ul | |
li(ng-repeat="chat in chatrooms") | |
.row(ng-show="usernameIsSet") | |
.col-xs-12 | |
ul.users | |
li(ng-repeat="user in users") | |
.avatar | |
.img(style="background-image:url({{user.picture}})", ng-class="{speak: isSpeaking && isSpeakingUser === user.id}") | |
p {{user.name}} | |
.row(ng-show="!usernameIsSet") | |
.col-xs-12 | |
.avatar(ng-class="user.name") | |
.img(style="background-image:url({{user.picture}}); margin-left:auto; margin-right:auto; width:120px; height: 120px;", ng-class="{speak: isSpeaking && isSpeakingUser === user.id}") | |
p {{user.name}} | |
// LOGIN FORM | |
.row | |
.col-xs-12 | |
.well(ng-show="!usernameIsSet") | |
form(name="login", ng-submit="login.$valid && setUser(user.chatroom)") | |
.form-group | |
label | |
i.fa.fa-user | |
| Username | |
input.form-control(type="text", novalidate, required, maxlength="15", ng-model="user.name", placeholder="Choose a username", ng-disabled="usernameIsSet") | |
.form-group(ng-show="!usernameIsSet") | |
label | |
i.fa.fa-picture-o | |
| Profile picture URL | |
input.form-control(type="text", novalidate, ng-model="user.picture", placeholder="picture", ng-disabled="usernameIsSet") | |
.form-group(ng-show="!usernameIsSet") | |
label | |
i.fa.fa-comments-o | |
| Chatrooms | |
.new-room.button.btn.btn-default.btn-sm.btn-link.pull-right(ng-click="createRoom()") | |
| Create new room | |
br | |
div | |
label.btn.btn-default(ng-repeat="chat in chats") | |
input#option1(type='radio', name='options', value="{{chat.$id}}", ng-model="user.chatroom", required, ng-disabled="countUsers(chat) >= 4") | |
ul.users__list.list-reset | |
li(ng-repeat="user in chat.users") | |
// img(ng-src="{{user.picture}}" style="width:30px") | |
// | {{user.name}} | |
.avatar(ng-class="user.name") | |
.img(style="background-image:url({{user.picture}}); margin-left:auto; margin-right:auto; ", ng-class="{speak: isSpeaking && isSpeakingUser === user.name}") | |
p.avatar__name {{user.name}} | |
small.chat__is-full(ng-if="countUsers(chat) >= 4") This chatroom is full. Please join another or create a new one. | |
// | Chat: {{user.chatroom}} | |
.form-group | |
button.btn.btn-success.btn-lg(type="submit", ng-if="!usernameIsSet") | |
| Start! | |
// /LOGIN FORM | |
.row(ng-show="usernameIsSet") | |
.col-xs-12 | |
form(ng-submit="submit()") | |
.form-group | |
input.form-control(type="text", novalidate, required, maxlength="50", placeholder="Your message" ng-model="user.message") | |
.form-group | |
// button.btn.btn-primary(type="submit") | |
| Send message | |
.row | |
.col-xs-12 | |
// Articoli | |
article.media(ng-repeat="item in chatMessages") {{item.text}} | |
//button.btn.btn-sm.btn-danger(ng-click="clear()") remove | |
// | |
.row | |
.col-xs-12 | |
pre | |
| {{users | json}} | |
// | |
.row | |
.col-xs-12 | |
a(href="https://twitter.com/share", class="twitter-share-button", data-via="afalchi82") Tweet | |
script | |
| !function(d,s,id){var js,fjs=d.getElementsByTagName(s)[0],p=/^http:/.test(d.location)?'http':'https';if(!d.getElementById(id)){js=d.createElement(s);js.id=id;js.src=p+'://platform.twitter.com/widgets.js';fjs.parentNode.insertBefore(js,fjs);}}(document, 'script', 'twitter-wjs'); | |
.row | |
.col-xs-12 | |
a(href="https://m1sc.firebaseio.com/chat/temp", target="_blank") Inspect this firebase | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
'use strict'; | |
// Console log utility | |
var cl = function($m){ console.log($m);}; | |
console.clear(); | |
angular.module('myApp', ['firebase']) | |
.run(function($rootScope, chatMessages, speechSynt, users, ChatsFB) { | |
var vm = $rootScope; | |
// Chatrooms | |
vm.chats = ChatsFB.arr(); | |
vm.createRoom = function () { | |
vm.chats.$add({messages: ''}); | |
}; | |
vm.user = { | |
chatroom: '', | |
name: 'Happy Uncle', | |
message: '', | |
id: Date.now(), | |
picture: 'https://cdn.pbrd.co/images/P93JuF9.png' | |
}; | |
// Set ChatID | |
var chatID = vm.user.chatroom; | |
vm.setUser = function ($chatID) { | |
vm.usernameIsSet = true; | |
vm.chatMessages = chatMessages.ref(vm.user.chatroom); | |
vm.chatMessagesArr = chatMessages.arr(vm.user.chatroom); | |
vm.users = ChatsFB.currentChatUsersArr($chatID); | |
vm.authObj = users.authObj; | |
vm.chat_id = chatMessages.id; | |
vm.isSpeaking = false; | |
vm.chatID = chatID; | |
// Save user in current chatroom | |
var currentChat = ChatsFB.currentChatUsersArr($chatID); | |
currentChat.$add(vm.user); | |
// Start speech | |
speechInit(); | |
}; | |
vm.submit = function () { | |
vm.chatMessagesArr.$add({ | |
user: vm.user.name, | |
text: vm.user.message, | |
id: vm.user.id, | |
date: Date.now() | |
}); | |
vm.user.message = ''; | |
}; | |
vm.clear = function () { | |
vm.chatMessages.ref.set(''); | |
}; | |
speechSynt.speech.onend = function () { | |
vm.$applyAsync(function () { | |
vm.isSpeaking = false; | |
}); | |
}; | |
// Read message | |
function speechInit () { | |
chatMessages.ref(vm.user.chatroom).limitToLast(1).on('child_added', function(childSnapshot, prevChildKey) { | |
speechSynt.talk(childSnapshot.val().text); | |
vm.$applyAsync(function () { | |
vm.isSpeaking = true; | |
vm.isSpeakingUser = childSnapshot.val().id; | |
cl(childSnapshot.val().id); | |
}); | |
}); | |
} | |
// User count method | |
vm.countUsers = function (chat) { | |
var count = 0; | |
for (var obj in chat.users) { | |
count++; | |
} | |
return count; | |
}; | |
}) | |
/* --------------------------------------------------------- | |
Services | |
----------------------------------------------------------*/ | |
.value('chatID', '') | |
.value('FBRoot', 'https://m1sc.firebaseio.com/chat/temp') | |
.factory('speechSynt', function() { | |
var voices = window.speechSynthesis.getVoices(), | |
speech = new SpeechSynthesisUtterance(); | |
speech.voice = voices[2]; // Note: some voices don't support altering params | |
speech.voice = speechSynthesis.getVoices().filter(function(voice) {return voice.name == 'Whisper';})[0] | |
speech.voiceURI = 'native'; | |
speech.volume = .8; // 0 to 1 | |
speech.rate = 1; // 0.1 to 10 | |
speech.pitch = 1; //0 to 2 | |
speech.lang = 'it-IT'; | |
// speech.lang = 'en-US'; | |
return { | |
speech: speech, | |
talk: function ($m) { | |
speech.text = $m; | |
speechSynthesis.speak(speech); | |
} | |
}; | |
}) | |
.factory('users', function(FBRoot, $firebaseArray){ | |
var ref = new Firebase(FBRoot + '/users'), | |
authObj; | |
ref.authAnonymously(function(error, authData) { | |
if (error) { | |
// console.log("Login Failed!", error); | |
} else { | |
// console.log("Authenticated successfully with payload:", authData); | |
authObj = authData; | |
} | |
}) | |
return { | |
fbArr: $firebaseArray(ref), | |
authObj: authObj | |
}; | |
}) | |
.factory('ChatsFB', function(FBRoot, $firebaseArray){ | |
return { | |
arr: function () { | |
var ref = new Firebase(FBRoot + '/chatrooms'); | |
return $firebaseArray(ref); | |
}, | |
currentChatUsersArr: function ($id) { | |
var ref = new Firebase(FBRoot + '/chatrooms/' + $id + '/users'); | |
return $firebaseArray(ref); | |
} | |
}; | |
}) | |
.factory("Presence", function() { | |
return { | |
ref: function (id) { | |
var ref = new Firebase(FBRoot + '/chatrooms/' + id + '/messages'); | |
return ref; | |
}, | |
arr: function (id) { | |
var ref = new Firebase(FBRoot + '/chatrooms/' + id + '/messages'); | |
return $firebaseArray(ref); | |
} | |
}; | |
}) | |
.factory("chatMessages", function(FBRoot, $firebaseArray) { | |
return { | |
ref: function (id) { | |
var ref = new Firebase(FBRoot + '/chatrooms/' + id + '/messages'); | |
return ref; | |
}, | |
arr: function (id) { | |
var ref = new Firebase(FBRoot + '/chatrooms/' + id + '/messages'); | |
return $firebaseArray(ref); | |
} | |
}; | |
}) | |
; | |
/* --------------------------------------------------------------- */ | |
// Manual bootstrapping Angular to check browser speech support first | |
/* --------------------------------------------------------------- */ | |
if ('speechSynthesis' in window) { | |
angular.element(document).ready(function() { | |
angular.bootstrap(document, ['myApp']); | |
}); | |
} else { | |
console.log('else'); | |
document.body.innerHTML = '<i class="fa fa-chrome" aria-hidden="true"></i> Please use Google Chrome.'; | |
} | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<script src="//cdnjs.cloudflare.com/ajax/libs/jquery/2.2.2/jquery.min.js"></script> | |
<script src="//maxcdn.bootstrapcdn.com/bootstrap/3.3.6/js/bootstrap.min.js"></script> | |
<script src="https://code.angularjs.org/1.3.15/angular.min.js"></script> | |
<script src="https://cdn.firebase.com/js/client/2.2.4/firebase.js"></script> | |
<script src="https://cdn.firebase.com/libs/angularfire/1.2.0/angularfire.min.js"></script> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
@import url(https://fonts.googleapis.com/css?family=Work+Sans:400,300,500); | |
@mixin size($w, $h) { width: $w; height: $h;} | |
@mixin square($s) { width: $s; height: $s;} | |
$accent: #F12E8F; | |
body { | |
font-family: 'Work Sans', sans-serif; | |
padding: 50px 0; | |
text-align: center; | |
// background-color: #5CB8B3; | |
} | |
.container { | |
max-width: 480px; | |
} | |
h1 { | |
font-weight: 800; | |
font-size: 45px; | |
margin-bottom: 30px; | |
.fa { | |
color: $accent; | |
} | |
small { | |
text-transform: uppercase; | |
font-size: 12px; | |
display: block; | |
} | |
} | |
form { | |
margin: 0 0 20px; | |
label, label.btn { | |
display: block; | |
text-align: left; | |
} | |
label.btn { | |
margin-bottom: 5px; | |
} | |
input { | |
// text-align: center; | |
} | |
[type="radio"] { | |
width:12px; | |
} | |
} | |
.avatar { | |
margin-bottom: 30px; | |
text-align: center; | |
text-transform: capitalize; | |
.img, .img:after { | |
background-size: cover; | |
border-radius: 60px; | |
} | |
.img { | |
margin: 30px 10px 10px; | |
transition: all .5s linear; | |
transform: scale(1); | |
position: relative; | |
width: 60px; | |
height: 60px; | |
z-index: 2; | |
&:after { | |
// background: url('https://cdn.pbrd.co/images/YowzOyh.png'); | |
background-size: cover; | |
content:''; | |
position: absolute; | |
top: 0; | |
left: 0; | |
width: 100%; | |
height: 100%; | |
z-index: 0; | |
} | |
} | |
} | |
.users { | |
margin: 0; | |
padding: 0; | |
text-align: center; | |
li { | |
display:inline-block; | |
list-style:none; | |
} | |
} | |
.users__list { | |
margin:0; padding: 0; | |
li { | |
list-style: none; | |
display: inline; | |
margin: 0 8px; | |
} | |
.avatar { | |
display: inline-block; | |
margin: 0 auto; | |
.img { | |
@include square(50px); | |
margin: 0 5px; | |
} | |
&__name {font-size:10px;} | |
} | |
} | |
.new-room { | |
margin-top: -5px; | |
} | |
.chat { | |
&__is-full { | |
font-size: 10px; | |
color: red; | |
} | |
} | |
.speak { | |
animation-name: speakAnim; | |
animation-duration: .1s; | |
animation-timing-function: ease-out; | |
animation-iteration-count: infinite; | |
animation-direction: alternate; | |
} | |
@keyframes speakAnim { | |
from { | |
transform: scale(1.2); | |
box-shadow: 0 0 0px $accent; | |
} | |
to { | |
transform: scale(1.22); | |
box-shadow: 0 0 5px $accent; | |
} | |
} | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css" rel="stylesheet" /> | |
<link href="https://cdnjs.cloudflare.com/ajax/libs/animate.css/3.5.1/animate.min.css" rel="stylesheet" /> | |
<link href="https://maxcdn.bootstrapcdn.com/font-awesome/4.6.2/css/font-awesome.min.css" rel="stylesheet" /> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment