Disconnected overlay, active contact selection, unread count badges, login screen

This commit is contained in:
Lance Stout 2013-09-11 20:59:50 -07:00
parent 67fc48f9be
commit 378f6e0a8b
13 changed files with 195 additions and 21 deletions

View File

@ -78,7 +78,7 @@ module.exports = function (client, app) {
}); });
client.on('disconnected', function () { client.on('disconnected', function () {
me.connectionStatus = 'disconnected'; me.connected = false;
}); });
client.on('auth:failed', function () { client.on('auth:failed', function () {
@ -89,7 +89,7 @@ module.exports = function (client, app) {
client.on('session:started', function (jid) { client.on('session:started', function (jid) {
me.jid = jid; me.jid = jid;
me.connectionStatus = 'connected'; me.connected = true;
client.getRoster(function (err, resp) { client.getRoster(function (err, resp) {
resp = resp.toJSON(); resp = resp.toJSON();
@ -186,6 +186,13 @@ module.exports = function (client, app) {
if (info.chatState === 'gone') { if (info.chatState === 'gone') {
contact.lockedResource = undefined; contact.lockedResource = undefined;
} }
} else if (me.isMe(info.from)) {
if (info.chatState === 'active' || info.chatState === 'composing') {
contact = me.getContact(info.to);
if (contact) {
contact.unreadCount = 0;
}
}
} }
}); });
@ -206,6 +213,9 @@ module.exports = function (client, app) {
// }); // });
//} //}
if (!contact.activeContact) {
contact.unreadCount++;
}
contact.messages.add(message); contact.messages.add(message);
if (!contact.lockedResource) { if (!contact.lockedResource) {
contact.lockedResource = msg.from.full; contact.lockedResource = msg.from.full;

View File

@ -66,6 +66,12 @@ module.exports = HumanModel.define({
return ''; return '';
} }
} }
},
hasUnread: {
deps: ['unreadCount'],
fn: function () {
return this.unreadCount > 0;
}
} }
}, },
session: { session: {
@ -77,7 +83,9 @@ module.exports = HumanModel.define({
chatState: ['string', true, 'gone'], chatState: ['string', true, 'gone'],
lockedResource: 'string', lockedResource: 'string',
lastSentMessage: 'object', lastSentMessage: 'object',
timezoneOffset: ['number', false, 0] timezoneOffset: ['number', false, 0],
activeContact: ['bool', true, false],
unreadCount: ['number', true, 0]
}, },
collections: { collections: {
resources: Resources, resources: Resources,

View File

@ -1,4 +1,4 @@
/*global app*/ /*global app, client*/
"use strict"; "use strict";
var HumanModel = require('human-model'); var HumanModel = require('human-model');
@ -14,12 +14,29 @@ module.exports = HumanModel.define({
session: { session: {
jid: ['object', true], jid: ['object', true],
status: ['string', true, ''], status: ['string', true, ''],
avatar: ['string', true, ''] avatar: ['string', true, ''],
connected: ['bool', true, false],
_activeContact: ['string', true, '']
}, },
collections: { collections: {
contacts: Contacts contacts: Contacts
}, },
setActiveContact: function (jid) {
var prev = this.getContact(this._activeContact);
if (prev) {
prev.activeContact = false;
}
var curr = this.getContact(jid);
if (curr) {
curr.activeContact = true;
curr.unreadCount = 0;
}
this._activeContact = jid;
},
getContact: function (jid, alt) { getContact: function (jid, alt) {
if (typeof jid === 'string') jid = new client.JID(jid);
if (typeof alt === 'string') alt = new client.JID(alt);
if (this.isMe(jid)) { if (this.isMe(jid)) {
jid = alt || jid; jid = alt || jid;
} }

View File

@ -1,4 +1,4 @@
/*global $, app*/ /*global $, app, me*/
"use strict"; "use strict";
var _ = require('underscore'); var _ = require('underscore');
@ -29,6 +29,10 @@ module.exports = HumanView.extend({
this.trigger('pageloaded'); this.trigger('pageloaded');
if (this.model.jid) {
me.setActiveContact(this.model.jid);
}
return this; return this;
}, },
hide: function () { hide: function () {
@ -45,6 +49,8 @@ module.exports = HumanView.extend({
this.animateRemove(); this.animateRemove();
} }
me.setActiveContact('');
return this; return this;
} }
}); });

View File

@ -12,7 +12,7 @@ exports.pages = {};
exports.body = function anonymous(locals) { exports.body = function anonymous(locals) {
var buf = []; var buf = [];
with (locals || {}) { with (locals || {}) {
buf.push('<body><div class="wrap"><header id="me"><img class="avatar"/><p class="status"></p></header><nav id="contactList"></nav><section id="pages"></section><footer></footer></div></body>'); buf.push('<body><div class="wrap"><div id="reconnect"></div><header id="me"><img class="avatar"/><p class="status"></p></header><nav class="main"><li><a href="/logout">Logout</a></li><li><a href="/">Home</a></li></nav><nav id="contactList"></nav><section id="pages"></section><footer></footer></div></body>');
} }
return buf.join(""); return buf.join("");
}; };
@ -35,7 +35,7 @@ exports.includes.contactListItem = function anonymous(locals) {
"class": "avatar" "class": "avatar"
}, { }, {
src: true src: true
}) + '/><div class="name">' + jade.escape(null == (jade.interp = contact.displayName) ? "" : jade.interp) + '</div><div class="status">' + jade.escape(null == (jade.interp = contact.status) ? "" : jade.interp) + "</div></li>"); }) + '/><div class="name">' + jade.escape(null == (jade.interp = contact.displayName) ? "" : jade.interp) + '</div><div class="unread">' + jade.escape(null == (jade.interp = contact.unreadCount) ? "" : jade.interp) + '</div><div class="status">' + jade.escape(null == (jade.interp = contact.status) ? "" : jade.interp) + "</div></li>");
} }
return buf.join(""); return buf.join("");
}; };

View File

@ -1,8 +1,14 @@
body body
.wrap .wrap
#reconnect
header#me header#me
img.avatar img.avatar
p.status p.status
nav.main
li
a(href="/logout") Logout
li
a(href="/") Home
nav#contactList nav#contactList
section#pages section#pages
footer footer

View File

@ -1,4 +1,5 @@
li.contact li.contact
img.avatar(src=contact.avatar) img.avatar(src=contact.avatar)
.name=contact.displayName .name=contact.displayName
.unread=contact.unreadCount
.status=contact.status .status=contact.status

View File

@ -11,11 +11,14 @@ module.exports = HumanView.extend({
classBindings: { classBindings: {
show: '', show: '',
subscription: '', subscription: '',
chatState: '' chatState: '',
activeContact: '',
hasUnread: ''
}, },
textBindings: { textBindings: {
displayName: '.name', displayName: '.name',
status: '.status' status: '.status',
unreadCount: '.unread'
}, },
srcBindings: { srcBindings: {
avatar: '.avatar' avatar: '.avatar'

View File

@ -11,6 +11,9 @@ module.exports = HumanView.extend({
events: { events: {
'click a[href]': 'handleLinkClick' 'click a[href]': 'handleLinkClick'
}, },
classBindings: {
connected: '#reconnect'
},
render: function () { render: function () {
$('head').append(templates.head()); $('head').append(templates.head());
this.renderAndBind(); this.renderAndBind();

BIN
public/logo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

View File

@ -4,6 +4,7 @@ html, body {
padding: 0px; padding: 0px;
margin: 0px; margin: 0px;
background-color: #ecf0f2; background-color: #ecf0f2;
color: #2e2d2d;
} }
#pages { #pages {
@ -14,11 +15,62 @@ html, body {
padding: 5px; padding: 5px;
} }
#reconnect {
z-index: 5000;
position: absolute;
left: 0px;
top: 0px;
height: 100%;
width: 100%;
background-color: rgba(0, 0, 0, .5);
}
#reconnect.connected {
display: none;
}
#me {
display: none;
}
nav.main {
background-color: #1C232D;
width: 176px;
border-right: 1px solid black;
padding: 5px;
margin: 0px;
text-align: center;
box-sizing: border-box;
position: fixed;
bottom: 0px;
left: 0px;
}
nav.main li {
display: inline-block;
margin: 5px;
}
nav.main a {
display: block;
text-decoration: none;
text-align: center;
border-radius: 3px;
border: none;
height: 20px;
padding: 0 1em;
color: white;
background-color: #333;
line-height: 20px;
font-size: 12px;
cursor: pointer;
box-sizing: border-box;
}
#contactList { #contactList {
top: 0px; top: 0px;
left: 0px; bottom: 40px;
width: 175px; width: 175px;
height: 100%;
background-color: #1C232D; background-color: #1C232D;
position: fixed; position: fixed;
overflow-y: auto; overflow-y: auto;
@ -122,6 +174,12 @@ html, body {
color: #777; color: #777;
} }
.contact.activeContact {
background-color: #35c8ff;
background-image: -moz-linear-gradient(top, #35c8ff, #00aeef);
background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0, #35c8ff), color-stop(1, #00aeef));
}
.chatView { .chatView {
position: relative; position: relative;
} }
@ -226,8 +284,18 @@ html, body {
font-size: 14px; font-size: 14px;
} }
#me { .contact .unread {
display: none; display: none;
color: white;
width: 20px;
border-radius: 10px;
position: relative;
text-align: center;
background-color: red;
}
.contact.hasUnread .unread {
display: block;
} }
#chatInput { #chatInput {
@ -270,9 +338,58 @@ html, body {
background-color: yellow; background-color: yellow;
} }
#loginForm { #loginbox {
margin: 50px; position: relative;
margin: auto;
margin-top: 5%;
padding: 20px;
background-color: white;
width: 75%;
} }
#loginForm label { #loginbox label {
display: block; display: block;
margin-bottom: 5px;
font-size: 13px;
font-weight: bold;
color: #777;
}
#loginbox input {
width: 100%;
display: block;
height: 35px;
font-size: 14px;
padding: 10px 0.5em;
margin-bottom: 15px;
background-color: #f9fafa;
border: 1px solid #eeeeee;
color: #2e2d2d;
box-sizing: border-box;
}
#loginbox input:focus {
border: 1px solid #a7d9eb;
outline: 0px;
}
#loginbox button {
text-decoration: none;
text-align: center;
border-radius: 3px;
border: none;
height: 35px;
padding: 0 1em;
color: white;
background-color: #7ec6e2;
line-height: 35px;
font-size: 16px;
cursor: pointer;
}
#loginbox h2 {
padding-bottom: 10px;
border-bottom: 1px solid #f8f8f8
}
.aux header {
margin-top: 10%;
text-align: center;
}
#logo {
margin: auto;
} }

View File

@ -51,8 +51,9 @@ app.get('/logout', function (req, res) {
app.get('*', clientApp.html()); app.get('*', clientApp.html());
https.createServer({ //https.createServer({
key: fs.readFileSync(config.http.key), // key: fs.readFileSync(config.http.key),
cert: fs.readFileSync(config.http.cert) // cert: fs.readFileSync(config.http.cert)
}, app).listen(config.http.port); //}, app).listen(config.http.port);
app.listen(config.http.port);
console.log('demo.stanza.io running at: ' + config.http.baseUrl); console.log('demo.stanza.io running at: ' + config.http.baseUrl);

View File

@ -7,7 +7,9 @@ html
link(rel="stylesheet", href="/styles.css") link(rel="stylesheet", href="/styles.css")
block head block head
body body.aux
header
img#logo(src="/logo.png", alt="OTalk")
block content block content
script(src='/zepto.js') script(src='/zepto.js')