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 () {
me.connectionStatus = 'disconnected';
me.connected = false;
});
client.on('auth:failed', function () {
@ -89,7 +89,7 @@ module.exports = function (client, app) {
client.on('session:started', function (jid) {
me.jid = jid;
me.connectionStatus = 'connected';
me.connected = true;
client.getRoster(function (err, resp) {
resp = resp.toJSON();
@ -186,6 +186,13 @@ module.exports = function (client, app) {
if (info.chatState === 'gone') {
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);
if (!contact.lockedResource) {
contact.lockedResource = msg.from.full;

View File

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

View File

@ -1,4 +1,4 @@
/*global app*/
/*global app, client*/
"use strict";
var HumanModel = require('human-model');
@ -14,12 +14,29 @@ module.exports = HumanModel.define({
session: {
jid: ['object', true],
status: ['string', true, ''],
avatar: ['string', true, '']
avatar: ['string', true, ''],
connected: ['bool', true, false],
_activeContact: ['string', true, '']
},
collections: {
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) {
if (typeof jid === 'string') jid = new client.JID(jid);
if (typeof alt === 'string') alt = new client.JID(alt);
if (this.isMe(jid)) {
jid = alt || jid;
}

View File

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

View File

@ -12,7 +12,7 @@ exports.pages = {};
exports.body = function anonymous(locals) {
var buf = [];
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("");
};
@ -35,7 +35,7 @@ exports.includes.contactListItem = function anonymous(locals) {
"class": "avatar"
}, {
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("");
};

View File

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

View File

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

View File

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

View File

@ -11,6 +11,9 @@ module.exports = HumanView.extend({
events: {
'click a[href]': 'handleLinkClick'
},
classBindings: {
connected: '#reconnect'
},
render: function () {
$('head').append(templates.head());
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;
margin: 0px;
background-color: #ecf0f2;
color: #2e2d2d;
}
#pages {
@ -14,11 +15,62 @@ html, body {
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 {
top: 0px;
left: 0px;
bottom: 40px;
width: 175px;
height: 100%;
background-color: #1C232D;
position: fixed;
overflow-y: auto;
@ -122,6 +174,12 @@ html, body {
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 {
position: relative;
}
@ -226,8 +284,18 @@ html, body {
font-size: 14px;
}
#me {
.contact .unread {
display: none;
color: white;
width: 20px;
border-radius: 10px;
position: relative;
text-align: center;
background-color: red;
}
.contact.hasUnread .unread {
display: block;
}
#chatInput {
@ -270,9 +338,58 @@ html, body {
background-color: yellow;
}
#loginForm {
margin: 50px;
#loginbox {
position: relative;
margin: auto;
margin-top: 5%;
padding: 20px;
background-color: white;
width: 75%;
}
#loginForm label {
#loginbox label {
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());
https.createServer({
key: fs.readFileSync(config.http.key),
cert: fs.readFileSync(config.http.cert)
}, app).listen(config.http.port);
//https.createServer({
// key: fs.readFileSync(config.http.key),
// cert: fs.readFileSync(config.http.cert)
//}, app).listen(config.http.port);
app.listen(config.http.port);
console.log('demo.stanza.io running at: ' + config.http.baseUrl);

View File

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