mirror of
https://github.com/moparisthebest/kaiwa
synced 2024-12-23 16:18:48 -05:00
Disconnected overlay, active contact selection, unread count badges, login screen
This commit is contained in:
parent
67fc48f9be
commit
378f6e0a8b
@ -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;
|
||||
|
@ -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,
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
});
|
||||
|
@ -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("");
|
||||
};
|
||||
|
@ -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
|
||||
|
@ -1,4 +1,5 @@
|
||||
li.contact
|
||||
img.avatar(src=contact.avatar)
|
||||
.name=contact.displayName
|
||||
.unread=contact.unreadCount
|
||||
.status=contact.status
|
||||
|
@ -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'
|
||||
|
@ -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
BIN
public/logo.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.7 KiB |
129
public/style.css
129
public/style.css
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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')
|
||||
|
Loading…
Reference in New Issue
Block a user