Squashed commit of the following:

commit 2b66f7cfccfeb7578b1ebdd6955464a29517566b
Author: Julian Lam <julian@nodebb.org>
Date:   Thu Jan 11 15:22:23 2018 -0500

    chat tweaks on persona and fixing taskbar integration for group chats

commit c4f6735025a981b4591f3d0b82e2897f72e43d4b
Author: Julian Lam <julian@nodebb.org>
Date:   Wed Jan 10 15:12:54 2018 -0500

    ported revamped vanilla chats page and modal to persona, nodebb/nodebb#6192
main
Julian Lam 7 years ago
parent 4f3544ab5f
commit 4c2e2f09da

@ -1,3 +1,173 @@
// Make chats page edge-to-edge
.page-user-chats {
padding-top: 50px;
#content.container {
width: auto;
padding: 0;
}
.navbar {
margin-bottom: 0;
}
#panel {
padding-top: 0px;
padding-bottom: 0px;
}
}
/* Styles common to both full chat and chat modal */
.chats-full, .chat-modal {
display: flex;
flex-wrap: nowrap;
[component="chat/nav-wrapper"] {
flex: 1;
flex-direction: column;
box-shadow: 0.5em 0 0.5em @gray-lighter;
.chats-list {
flex: 1;
overflow-y: auto;
}
.chat-search {
background-color: @panel-default-heading-bg;
border-bottom: 1px solid @gray-dark;
input {
background-color: @panel-default-heading-bg;
border-radius: 0;
border: none;
height: ~"calc(3em - 1px)";
}
ul {
width: 100%;
}
}
[component="chat/search/list"] {
padding: 0;
overflow-x: hidden;
overflow-y: auto;
border-top: 1px solid @gray-lighter;
li {
position: relative;
clear: both;
list-style-type: none;
padding: .5em;
height: 70px;
cursor: pointer;
border-left: 1px solid;
border-right: 1px solid;
border-bottom: 1px solid;
border-color: #eee;
background: #fff;
i {
position: relative;
left: -30px;
font-size: 20px;
top: -20px;
}
img, .user-icon {
.user-icon-style(50px, 2.4rem, 50%);
margin-top: 4px;
margin-right: 13px;
margin-left: .5em;
}
}
}
}
[component="chat/main-wrapper"] {
flex: 3;
.alert {
margin: 1em;
}
}
[component="chat/messages"] {
display: flex;
flex-direction: column;
height: 100%;
.chat-content {
flex: 1;
}
}
[component="chat/header"] {
padding: @panel-heading-padding;
background-color: @panel-default-heading-bg;
border-bottom: 1px solid @gray-dark;
span {
font-weight: 500;
}
.close {
margin-left: 0.5em;
}
.members {
a {
font-weight: 600;
color: @gray-dark;
}
}
.dropdown {
float: right;
.avatar {
margin-right: 0.5em;
}
}
}
.modal-header .dropdown {
float: right;
.avatar {
margin-right: 0.5em;
}
}
[component="chat/composer"] {
display: flex;
position: relative;
[component="chat/input"] {
flex: 1;
background: none;
box-shadow: none;
border: 0;
border: 1px solid @gray-lighter;
border-radius: 0;
}
[data-action="send"] {
width: 5em;
height: 100%;
}
[component="chat/message/remaining"] {
position: absolute;
float: right;
right: 5.25em;
z-index: 2;
bottom: 0;
color: @gray-light;
}
}
}
.chats-page {
margin-top: 10px;
}
@ -12,7 +182,6 @@
overflow-x: hidden;
overflow-y: auto;
border-top: 1px solid @gray-lighter;
max-width: 360px;
> li {
position: relative;
@ -109,6 +278,7 @@
.members {
padding-left: 1rem;
margin-bottom: 0.5rem;
z-index: 1;
position: absolute;
bottom: 2px;
@ -165,7 +335,8 @@
z-index: 10000;
}
.expanded-chat, .chat-modal {
/* Chat modal specific styles */
.chat-modal {
.modal-header {
padding: 0.25em 1em;
@ -193,9 +364,20 @@
}
}
.modal-body {
display: flex;
flex-direction: column;
height: 400px;
.chat-content {
flex: 1;
}
}
}
.expanded-chat, .chat-modal {
.chat-content {
.fix-lists;
height: 250px;
overflow-y: auto;
overflow-x: hidden;
resize: none;
@ -267,6 +449,7 @@
.message-body {
margin-left: 45px;
overflow-y: hidden;
p {
margin: 7px 0 0 0;
@ -298,10 +481,6 @@
}
}
.chat-input {
height: 42px;
}
.user-typing {
color: @gray-light;
margin: 1.428rem 0;
@ -317,7 +496,6 @@
textarea {
resize: none;
height: 42px;
}
.since-bar {
@ -346,38 +524,32 @@
}
}
[component="chat/search/list"] {
[component="chat/manage-modal"] {
.list-group-item .avatar {
border-radius: 0;
margin-right: 1em;
}
padding: 0;
overflow-x: hidden;
overflow-y: auto;
border-top: 1px solid @gray-lighter;
div+span {
margin: -4px;
}
}
li {
position: relative;
clear: both;
list-style-type: none;
padding: .5em;
height: 70px;
cursor: pointer;
border-left: 1px solid;
border-right: 1px solid;
border-bottom: 1px solid;
border-color: #eee;
background: #fff;
/* Mobile handling of chat page */
@media (max-width: @screen-sm) {
.page-user-chats {
padding-bottom: 0;
i {
position: relative;
left: -30px;
font-size: 20px;
top: -20px;
[component="chat/nav-wrapper"][data-loaded="1"] {
display: none;
}
img, .user-icon {
.user-icon-style(50px, 2.4rem, 50%);
margin-top: 4px;
margin-right: 13px;
margin-left: .5em;
[component="chat/nav-wrapper"][data-loaded="0"] + [component="chat/main-wrapper"] {
display: none;
}
}
[data-action="pop-out"] {
display: none;
}
}

@ -92,7 +92,7 @@
.user-icon-style(50px, 2.4rem, 50%) !important;
padding: 0;
color: white;
background: none;
background: @brand-primary;
background-size: cover;
i {

@ -33,7 +33,7 @@ $(document).ready(function() {
data.options.className = 'taskbar-' + data.module;
if (data.module === 'composer') {
data.options.icon = 'fa-plus';
data.options.icon = 'fa-commenting-o';
} else if (data.module === 'chat') {
if (!data.element.length) {
createChatIcon(data);
@ -54,19 +54,21 @@ $(document).ready(function() {
});
function createChatIcon(data) {
data.options.icon = 'fa-spinner fa-spin';
$.getJSON(config.relative_path + '/api/user/' + utils.slugify(data.options.title), function(user) {
$.getJSON(config.relative_path + '/api/user/' + app.user.userslug + '/chats/' + data.options.roomId, function(chatObj) {
var el = $('#taskbar [data-uuid="' + data.uuid + '"] a');
el.find('i').remove();
el.parent('[data-uuid]').attr('data-roomId', data.options.roomId);
if (user.picture) {
el.css('background-image', 'url(' + user.picture + ')');
} else {
el .css('background-color', user['icon:bgColor'])
.text(user['icon:text'])
.addClass('user-icon');
if (chatObj.users.length === 1) {
var user = chatObj.users[0];
el.find('i').remove();
if (user.picture) {
el.css('background-image', 'url(' + user.picture + ')');
} else {
el .css('background-color', user['icon:bgColor'])
.text(user['icon:text'])
.addClass('user-icon');
}
}
});
}

@ -1,24 +1,42 @@
<div id="chat-modal" class="chat-modal hide" tabindex="-1" role="dialog" aria-labelledby="Chat" aria-hidden="true" data-backdrop="none">
<div id="chat-modal" class="chat-modal hide" tabindex="-1" role="dialog" aria-labelledby="Chat" aria-hidden="true" data-backdrop="none" data-name="{roomName}">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button id="chat-close-btn" type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
<button type="button" class="close hidden-xs hidden-sm" data-action="maximize"><span aria-hidden="true"><i class="fa fa-expand"></i></span><span class="sr-only">[[modules:chat.maximize]]</span></button>
<button type="button" class="close hidden-xs hidden-sm" data-action="minimize"><span aria-hidden="true"><i class="fa fa-minus"></i></span><span class="sr-only">[[modules:chat.minimize]]</span></button>
<button class="close" component="chat/controlsToggle"><i class="fa fa-gear"></i></button>
<h4><!-- IF roomName -->{roomName}<!-- ELSE -->{usernames}<!-- ENDIF roomName --></h4>
<div class="dropdown">
<button class="close" data-toggle="dropdown" component="chat/controlsToggle"><i class="fa fa-gear"></i></button>
<ul class="dropdown-menu dropdown-menu-right" component="chat/controls">
<!-- IF users.length -->
<li class="dropdown-header">[[modules:chat.in-room]]</li>
<!-- BEGIN users -->
<li>
<a href="{config.relative_path}/uid/{../uid}">
<!-- IF ../picture -->
<img class="avatar avatar-sm" component="user/picture" src="{../picture}" align="left" itemprop="image" />
<!-- ELSE -->
<div class="avatar avatar-sm" component="user/picture" style="background-color: {../icon:bgColor};">{../icon:text}</div><!-- END -->{../username}
</a>
</li>
<!-- END -->
<li role="separator" class="divider"></li>
<!-- END -->
<li class="dropdown-header">[[modules:chat.options]]</li>
<li>
<a href="#" data-action="members"><i class="fa fa-fw fa-plus"></i> [[modules:chat.add-users-to-room]]</a>
</li>
<li>
<a href="#" data-action="rename"><i class="fa fa-fw fa-edit"></i> [[modules:chat.rename-room]]</a>
</li>
<li>
<a href="#" data-action="leave"><i class="fa fa-fw fa-sign-out"></i> [[modules:chat.leave]]</a>
</li>
</ul>
</div>
<form component="chat/controls" style="display: none;">
<!-- IF showUserInput -->
<div class="users-tag-container">
<input class="users-tag-input" type="text" class="form-control" placeholder="enter users here" tabindex="4"/>
</div>
<!-- ENDIF showUserInput -->
<input class="form-control" component="chat/room/name" value="{roomName}" <!-- IF !isOwner -->disabled<!-- ENDIF !isOwner -->/>
</form>
<h4 component="chat/room/name"><!-- IF roomName -->{roomName}<!-- ELSE -->{usernames}<!-- ENDIF roomName --></h4>
</div>
<div class="modal-body">
@ -26,13 +44,11 @@
<!-- IMPORT partials/chats/messages.tpl -->
</ul>
<div class="input-group">
<textarea component="chat/input" id="chat-message-input" rows="1" placeholder="[[modules:chat.placeholder]]" name="chat-message" class="form-control" <!-- IF !canReply -->readonly<!-- ENDIF !canReply -->></textarea>
<span class="input-group-btn">
<button id="chat-message-send-btn" class="btn btn-primary" href="#" type="button" <!-- IF !canReply -->disabled<!-- ENDIF !canReply -->>[[modules:chat.send]]</button>
</span>
<div component="chat/composer">
<textarea component="chat/input" placeholder="[[modules:chat.placeholder]]" class="form-control chat-input mousetrap" rows="1"></textarea>
<button class="btn btn-primary" type="button" data-action="send">[[modules:chat.send]]</button>
<span component="chat/message/remaining">{maximumChatMessageLength}</span>
</div>
<span component="chat/message/length">0</span>/<span>{maximumChatMessageLength}</span>
</div>
</div>
</div>

@ -1,19 +1,16 @@
<div class="row chats-page">
<div class="col-md-4" component="chat/nav-wrapper">
<div class="chat-search hidden-xs">
<input class="form-control" type="text" component="chat/search" placeholder="[[users:enter_username]]" />
<div class="chats-full">
<div component="chat/nav-wrapper" data-loaded="<!-- IF roomId -->1<!-- ELSE -->0<!-- END -->">
<div class="chat-search dropdown">
<input class="form-control" type="text" component="chat/search" placeholder="[[users:enter_username]]" data-toggle="dropdown" />
<ul component="chat/search/list" class="dropdown-menu"></ul>
</div>
<ul component="chat/search/list" class="chat-search-list">
</ul>
<ul component="chat/recent" class="chats-list" data-nextstart="{nextStart}">
<!-- BEGIN rooms -->
<!-- IMPORT partials/chats/recent_room.tpl -->
<!-- END rooms -->
</ul>
</div>
<div class="col-md-8 hidden-sm hidden-xs" component="chat/main-wrapper">
<div component="chat/main-wrapper">
<!-- IMPORT partials/chats/message-window.tpl -->
</div>
</div>
</div>

@ -1,29 +1,52 @@
<!-- IF roomId -->
<div component="chat/messages" class="expanded-chat" data-roomid="{roomId}">
<button type="button" class="close" data-action="pop-out"><span aria-hidden="true"><i class="fa fa-compress"></i></span><span class="sr-only">[[modules:chat.pop-out]]</span></button>
<button class="close controlsToggle" component="expanded-chat/controlsToggle"><i class="fa fa-gear"></i></button>
<div class="controls hide" component="expanded-chat/controls">
<!-- IF showUserInput -->
<div class="users-tag-container">
<input class="users-tag-input" type="text" class="form-control" placeholder="[[modules:chat.add-users-to-room]]" tabindex="4"/>
<div component="chat/header">
<button type="button" class="close" data-action="pop-out"><span aria-hidden="true"><i class="fa fa-compress"></i></span><span class="sr-only">[[modules:chat.pop-out]]</span></button>
<div class="dropdown">
<button class="close" data-toggle="dropdown" component="chat/controlsToggle"><i class="fa fa-gear"></i></button>
<ul class="dropdown-menu dropdown-menu-right" component="chat/controls">
<!-- IF users.length -->
<li class="dropdown-header">[[modules:chat.in-room]]</li>
<!-- BEGIN users -->
<li>
<a href="{config.relative_path}/uid/{../uid}">
<!-- IF ../picture -->
<img class="avatar avatar-sm" component="user/picture" src="{../picture}" align="left" itemprop="image" />
<!-- ELSE -->
<div class="avatar avatar-sm" component="user/picture" style="background-color: {../icon:bgColor};">{../icon:text}</div><!-- END -->{../username}
</a>
</li>
<!-- END -->
<li role="separator" class="divider"></li>
<!-- END -->
<li class="dropdown-header">[[modules:chat.options]]</li>
<li>
<a href="#" data-action="members"><i class="fa fa-fw fa-plus"></i> [[modules:chat.add-users-to-room]]</a>
</li>
<li>
<a href="#" data-action="rename"><i class="fa fa-fw fa-edit"></i> [[modules:chat.rename-room]]</a>
</li>
<li>
<a href="#" data-action="leave"><i class="fa fa-fw fa-sign-out"></i> [[modules:chat.leave]]</a>
</li>
</ul>
</div>
<!-- ENDIF showUserInput -->
<input class="form-control" component="chat/room/name" value="{roomName}" <!-- IF !isOwner -->disabled<!-- ENDIF !isOwner -->/>
<hr />
<span class="members">
[[modules:chat.chatting_with]]:
<!-- BEGIN users -->
<a href="{config.relative_path}/uid/{../uid}">{../username}</a><!-- IF !@last -->,<!-- END -->
<!-- END -->
</span>
</div>
<ul class="chat-content">
<!-- IMPORT partials/chats/messages.tpl -->
</ul>
<div class="input-group">
<textarea component="chat/input" placeholder="[[modules:chat.placeholder]]" class="form-control chat-input mousetrap" rows="1" <!-- IF !canReply -->readonly<!-- ENDIF !canReply -->></textarea>
<span class="input-group-btn">
<button class="btn btn-primary" type="button" data-action="send" <!-- IF !canReply -->disabled<!-- ENDIF !canReply -->>[[modules:chat.send]]</button>
</span>
<div component="chat/composer">
<textarea component="chat/input" placeholder="[[modules:chat.placeholder]]" class="form-control chat-input mousetrap" rows="2"></textarea>
<button class="btn btn-primary" type="button" data-action="send"><i class="fa fa-fw fa-2x fa-paper-plane"></i></button>
<span component="chat/message/remaining">{maximumChatMessageLength}</span>
</div>
<span component="chat/message/length">0</span>/<span>{maximumChatMessageLength}</span>
</div>
<!-- ELSE -->
<div class="alert alert-info">

@ -1,10 +1,9 @@
<li component="chat/recent/room" data-roomid="{rooms.roomId}" class="<!-- IF rooms.unread -->unread<!-- ENDIF rooms.unread -->">
<i class="fa fa-times pull-right leave" component="chat/leave"></i>
<strong class="room-name">
<!-- IF !rooms.lastUser.uid -->
<span>[[modules:chat.no-users-in-room]]</span>
<!-- ELSE -->
<!-- IF rooms.roomName -->{rooms.roomName}<!-- ELSE -->{rooms.usernames}<!-- ENDIF rooms.roomName -->
<span component="chat/title"><!-- IF rooms.roomName -->{rooms.roomName}<!-- ELSE -->{rooms.usernames}<!-- ENDIF rooms.roomName --></span>
<!-- ENDIF !rooms.lastUser.uid -->
</strong>
<div class="avatar-placeholder"></div>
@ -23,9 +22,4 @@
</li>
<!-- END rooms.users -->
</ul>
<!-- IF rooms.teaser.content -->
<span class="teaser-content">{rooms.teaser.content}</span>
<span class="teaser-timestamp timeago pull-right" title="{rooms.teaser.timestampISO}"></span>
<!-- ENDIF rooms.teaser.content -->
</li>

@ -0,0 +1,11 @@
<div class="form-group">
<input class="form-control" type="text" placeholder="[[global:user-search-prompt]]" />
<p class="text-danger"></p>
<p class="help-block">[[modules:chat.add-user-help]]</p>
<hr />
<ul class="list-group">
<li class="list-group-item"><i class="fa fa-spinner fa-spin"></i> [[modules:chat.retrieving-users]]</li>
</ul>
</div>

@ -0,0 +1,11 @@
<!-- BEGIN users -->
<li class="list-group-item">
<!-- IF ../picture -->
<img class="avatar avatar-sm" component="user/picture" data-uid="{../uid}" src="{../picture}" align="left" itemprop="image" />
<!-- ELSE -->
<div class="avatar avatar-sm" component="user/picture" data-uid="{../uid}" style="background-color: {../icon:bgColor};">{../icon:text}</div>
<!-- ENDIF ../picture -->
<span>{../username}</span>
</li>
<!-- END -->

@ -0,0 +1,4 @@
<input type="text" class="form-control" id="roomName" placeholder="[[modules:chat.rename-placeholder]]" value="{name}" />
<p class="help-block">
[[modules:chat.rename-help]]
</p>
Loading…
Cancel
Save