Cleanup chat/userlist to use flexbox, fix a couple of bugs
This commit is contained in:
parent
cbf82a1bc7
commit
e719e4ff81
@ -498,8 +498,8 @@ kbd {
|
||||
float: right;
|
||||
}
|
||||
|
||||
#viewport.rt #chat .sidebar {
|
||||
right: -180px;
|
||||
#viewport.rt #chat .userlist {
|
||||
display: none;
|
||||
}
|
||||
|
||||
#sidebar {
|
||||
@ -954,7 +954,8 @@ button.collapse-network:first-child:nth-last-child(3) {
|
||||
}
|
||||
|
||||
#chat .chan.active {
|
||||
display: block;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
#chat .condensed {
|
||||
@ -1006,48 +1007,40 @@ button.collapse-network:first-child:nth-last-child(3) {
|
||||
|
||||
#windows #form .input,
|
||||
.messages .msg,
|
||||
.sidebar {
|
||||
.userlist {
|
||||
font-size: 14px;
|
||||
line-height: 1.4;
|
||||
}
|
||||
|
||||
#windows #chat .header {
|
||||
display: flex;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
#chat .chat,
|
||||
#chat .sidebar {
|
||||
top: 48px;
|
||||
#chat .chat-content {
|
||||
display: flex;
|
||||
flex-grow: 1;
|
||||
}
|
||||
|
||||
#chat .chat {
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
overflow: auto;
|
||||
will-change: transform, scroll-position;
|
||||
-webkit-overflow-scrolling: touch;
|
||||
position: absolute;
|
||||
display: flex;
|
||||
flex-grow: 1;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
#chat .channel .chat {
|
||||
right: 180px;
|
||||
-webkit-overflow-scrolling: touch;
|
||||
}
|
||||
|
||||
#viewport.rt .chat {
|
||||
right: 0;
|
||||
}
|
||||
|
||||
#chat .sidebar {
|
||||
#chat .userlist {
|
||||
background: #fff;
|
||||
border-left: 1px solid #e7e7e7;
|
||||
bottom: 0;
|
||||
position: absolute;
|
||||
right: 0;
|
||||
width: 180px;
|
||||
transition: right 0.4s;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex-shrink: 0;
|
||||
touch-action: pan-y;
|
||||
}
|
||||
|
||||
@ -1456,16 +1449,13 @@ part/quit messages where we don't load previews (adds a blank line otherwise) */
|
||||
display: none;
|
||||
}
|
||||
|
||||
#chat .count {
|
||||
#chat .userlist .count {
|
||||
background: #fafafa;
|
||||
height: 48px;
|
||||
left: 0;
|
||||
position: absolute;
|
||||
right: 0;
|
||||
top: 0;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
#chat .search {
|
||||
#chat .userlist .search {
|
||||
color: #222;
|
||||
border: 0;
|
||||
background: none;
|
||||
@ -1476,17 +1466,14 @@ part/quit messages where we don't load previews (adds a blank line otherwise) */
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
#chat .names {
|
||||
bottom: 0;
|
||||
#chat .userlist .names {
|
||||
flex-grow: 1;
|
||||
overflow: auto;
|
||||
overflow-x: hidden;
|
||||
will-change: transform, scroll-position;
|
||||
-webkit-overflow-scrolling: touch;
|
||||
padding-bottom: 10px;
|
||||
position: absolute;
|
||||
top: 48px;
|
||||
width: 100%;
|
||||
touch-action: pan-y;
|
||||
-webkit-overflow-scrolling: touch;
|
||||
}
|
||||
|
||||
#chat .names-filtered {
|
||||
@ -1973,7 +1960,7 @@ part/quit messages where we don't load previews (adds a blank line otherwise) */
|
||||
.context-menu-item:hover,
|
||||
.textcomplete-item:hover,
|
||||
.textcomplete-menu .active,
|
||||
#chat .users .user.active {
|
||||
#chat .userlist .user.active {
|
||||
background-color: #f6f6f6;
|
||||
transition: none;
|
||||
}
|
||||
@ -2320,10 +2307,6 @@ part/quit messages where we don't load previews (adds a blank line otherwise) */
|
||||
left: 0;
|
||||
}
|
||||
|
||||
#chat .chat {
|
||||
right: 0;
|
||||
}
|
||||
|
||||
#viewport .lt,
|
||||
#viewport .channel .rt {
|
||||
display: flex;
|
||||
@ -2333,16 +2316,17 @@ part/quit messages where we don't load previews (adds a blank line otherwise) */
|
||||
display: block;
|
||||
}
|
||||
|
||||
#chat .channel .chat {
|
||||
#chat .userlist {
|
||||
height: 100%;
|
||||
position: absolute;
|
||||
right: 0;
|
||||
transform: translateX(180px);
|
||||
transition: transform 0.2s;
|
||||
}
|
||||
|
||||
#chat .sidebar {
|
||||
right: -180px;
|
||||
}
|
||||
|
||||
#viewport.rt #chat .sidebar {
|
||||
right: 0;
|
||||
#viewport.rt #chat .userlist {
|
||||
display: flex;
|
||||
transform: translateX(0);
|
||||
}
|
||||
|
||||
#chat .header .title {
|
||||
|
@ -263,7 +263,7 @@ function fuzzyGrep(term, array) {
|
||||
|
||||
function rawNicks() {
|
||||
const chan = chat.find(".active");
|
||||
const users = chan.find(".users");
|
||||
const users = chan.find(".userlist");
|
||||
|
||||
// If this channel has a list of nicks, just return it
|
||||
if (users.length > 0) {
|
||||
|
@ -41,11 +41,12 @@ $(function() {
|
||||
}
|
||||
});
|
||||
|
||||
viewport.on("click", ".rt", function(e) {
|
||||
viewport.on("click", ".rt", function() {
|
||||
const self = $(this);
|
||||
viewport.toggleClass(self.prop("class"));
|
||||
e.stopPropagation();
|
||||
chat.find(".chan.active .chat").trigger("msg.sticky");
|
||||
chat.find(".chan.active .chat").trigger("keepToBottom");
|
||||
|
||||
return false;
|
||||
});
|
||||
|
||||
function positionContextMenu(that, e) {
|
||||
@ -212,7 +213,7 @@ $(function() {
|
||||
+ Math.round(parseFloat(style.borderBottomWidth) || 0)
|
||||
) + "px";
|
||||
|
||||
chat.find(".chan.active .chat").trigger("msg.sticky"); // fix growing
|
||||
chat.find(".chan.active .chat").trigger("keepToBottom"); // fix growing
|
||||
});
|
||||
|
||||
let focus = $.noop;
|
||||
@ -553,7 +554,7 @@ $(function() {
|
||||
text: "/whois " + itemData,
|
||||
});
|
||||
|
||||
$(`.channel.active .users .user[data-name="${itemData}"]`).trigger("click");
|
||||
$(`.channel.active .userlist .user[data-name="${itemData}"]`).trigger("click");
|
||||
},
|
||||
query: function(itemData) {
|
||||
const chan = utils.findCurrentNetworkChan(itemData);
|
||||
|
@ -158,7 +158,7 @@ function renderUnreadMarker(template, firstUnread, channel) {
|
||||
}
|
||||
|
||||
function renderChannelUsers(data) {
|
||||
const users = chat.find("#chan-" + data.id).find(".users");
|
||||
const users = chat.find("#chan-" + data.id).find(".userlist");
|
||||
const nicks = data.users
|
||||
.concat() // Make a copy of the user list, sort is applied in-place
|
||||
.sort((a, b) => b.lastMessage - a.lastMessage)
|
||||
@ -167,7 +167,7 @@ function renderChannelUsers(data) {
|
||||
// Before re-rendering the list of names, there might have been an entry
|
||||
// marked as active (i.e. that was highlighted by keyboard navigation).
|
||||
// It is `undefined` if there was none.
|
||||
const previouslyActive = users.find(".active").data("name");
|
||||
const previouslyActive = users.find(".active");
|
||||
|
||||
const search = users
|
||||
.find(".search")
|
||||
@ -185,11 +185,11 @@ function renderChannelUsers(data) {
|
||||
|
||||
// If a nick was highlighted before re-rendering the lists, re-highlight it in
|
||||
// the newly-rendered list.
|
||||
if (previouslyActive) {
|
||||
if (previouslyActive.length > 0) {
|
||||
// We need to un-highlight everything first because triggering `input` with
|
||||
// a value highlights the first entry.
|
||||
users.find(".user").removeClass("active");
|
||||
users.find(`.user[data-name="${previouslyActive}"]`).addClass("active");
|
||||
users.find(`.user[data-name="${previouslyActive.data("name")}"]`).addClass("active");
|
||||
}
|
||||
|
||||
return users;
|
||||
|
@ -102,7 +102,7 @@ function processReceivedMessage(data) {
|
||||
}
|
||||
|
||||
if ((data.msg.type === "message" || data.msg.type === "action") && channel.hasClass("channel")) {
|
||||
const nicks = channel.find(".users").data("nicks");
|
||||
const nicks = channel.find(".userlist").data("nicks");
|
||||
|
||||
if (nicks) {
|
||||
const find = nicks.indexOf(data.msg.from.nick);
|
||||
|
@ -8,9 +8,9 @@ const templates = require("../views");
|
||||
|
||||
const chat = $("#chat");
|
||||
|
||||
chat.on("input", ".users .search", function() {
|
||||
chat.on("input", ".userlist .search", function() {
|
||||
const value = $(this).val();
|
||||
const parent = $(this).closest(".users");
|
||||
const parent = $(this).closest(".userlist");
|
||||
const names = parent.find(".names-original");
|
||||
const container = parent.find(".names-filtered");
|
||||
|
||||
@ -42,22 +42,24 @@ chat.on("input", ".users .search", function() {
|
||||
container.find(".user").first().addClass("active");
|
||||
});
|
||||
|
||||
chat.on("mouseenter", ".users .user", function() {
|
||||
chat.on("mouseenter", ".userlist .user", function() {
|
||||
// Reset any potential selection, this is required in cas there is already a
|
||||
// nick previously selected by keyboard
|
||||
$(".users .user").removeClass("active");
|
||||
$(this).parent().find(".user.active").removeClass("active");
|
||||
|
||||
$(this).addClass("active");
|
||||
});
|
||||
|
||||
chat.on("mouseleave", ".users .user", function() {
|
||||
chat.on("mouseleave", ".userlist .user", function() {
|
||||
// Reset any potential selection
|
||||
$(".users .user").removeClass("active");
|
||||
$(this).parent().find(".user.active").removeClass("active");
|
||||
});
|
||||
|
||||
exports.handleKeybinds = function(input) {
|
||||
Mousetrap(input.get(0)).bind(["up", "down"], (_e, key) => {
|
||||
const userlists = input.closest(".users");
|
||||
Mousetrap(input.get(0)).bind(["up", "down"], (e, key) => {
|
||||
e.preventDefault();
|
||||
|
||||
const userlists = input.closest(".userlist");
|
||||
let userlist;
|
||||
|
||||
// If input field has content, use the filtered list instead
|
||||
@ -69,13 +71,17 @@ exports.handleKeybinds = function(input) {
|
||||
|
||||
const users = userlist.find(".user");
|
||||
|
||||
if (users.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Find which item in the array of users is currently selected, if any.
|
||||
// Returns -1 if none.
|
||||
const activeIndex = users.toArray()
|
||||
.findIndex((user) => user.classList.contains("active"));
|
||||
|
||||
// Now that we know which user is active, reset any selection
|
||||
userlists.find(".user").removeClass("active");
|
||||
userlist.find(".user.active").removeClass("active");
|
||||
|
||||
// Mark next/previous user as active.
|
||||
if (key === "down") {
|
||||
@ -87,23 +93,13 @@ exports.handleKeybinds = function(input) {
|
||||
}
|
||||
|
||||
// Adjust scroll when active item is outside of the visible area
|
||||
const userlistHeight = userlist.height();
|
||||
const userlistScroll = userlist.scrollTop();
|
||||
const active = $(".user.active");
|
||||
const activeTop = active.position().top;
|
||||
const activeHeight = active.height();
|
||||
|
||||
if (activeTop > userlistHeight - activeHeight) {
|
||||
userlist.scrollTop(userlistScroll + activeTop - userlistHeight + activeHeight);
|
||||
} else if (activeTop < 0) {
|
||||
userlist.scrollTop(userlistScroll + activeTop - activeHeight);
|
||||
}
|
||||
userlist.find(".user.active")[0].scrollIntoView(false);
|
||||
});
|
||||
|
||||
// When pressing Enter, open the context menu (emit a click) on the active
|
||||
// user
|
||||
Mousetrap(input.get(0)).bind("enter", () => {
|
||||
const user = input.closest(".users").find(".user.active");
|
||||
const user = input.closest(".userlist").find(".user.active");
|
||||
|
||||
if (user.length) {
|
||||
const clickEvent = new $.Event("click");
|
||||
|
@ -48,7 +48,7 @@ function hasRoleInChannel(channel, roles) {
|
||||
const channelID = channel.data("id");
|
||||
const network = $("#sidebar .network").has(`.chan[data-id="${channelID}"]`);
|
||||
const ownNick = network.data("nick");
|
||||
const user = channel.find(`.users .user[data-name="${escape(ownNick)}"]`).first();
|
||||
const user = channel.find(`.names-original .user[data-name="${escape(ownNick)}"]`).first();
|
||||
return user.parent().is("." + roles.join(", ."));
|
||||
}
|
||||
|
||||
|
@ -91,7 +91,7 @@ a:hover,
|
||||
|
||||
#windows .header .topic,
|
||||
.messages .msg,
|
||||
.sidebar {
|
||||
.userlist {
|
||||
line-height: 1.8;
|
||||
}
|
||||
|
||||
|
@ -31,7 +31,7 @@ body {
|
||||
}
|
||||
|
||||
#main,
|
||||
#chat .sidebar,
|
||||
#chat .userlist,
|
||||
#windows .chan,
|
||||
#windows .window {
|
||||
background: #333c4a;
|
||||
@ -50,7 +50,7 @@ body {
|
||||
#chat .content,
|
||||
#windows .header,
|
||||
#chat .user-mode::before,
|
||||
#chat .sidebar {
|
||||
#chat .userlist {
|
||||
border-color: #2a323d;
|
||||
}
|
||||
|
||||
|
@ -32,7 +32,7 @@ body {
|
||||
}
|
||||
|
||||
#main,
|
||||
#chat .sidebar,
|
||||
#chat .userlist,
|
||||
#windows .chan,
|
||||
#windows .window {
|
||||
background: #3f3f3f;
|
||||
@ -76,7 +76,7 @@ body {
|
||||
#chat .content,
|
||||
#windows .header,
|
||||
#chat .user-mode::before,
|
||||
#chat .sidebar {
|
||||
#chat .userlist {
|
||||
border-color: #333;
|
||||
}
|
||||
|
||||
|
@ -18,22 +18,22 @@
|
||||
</span>
|
||||
{{/equal}}
|
||||
</div>
|
||||
<div class="chat">
|
||||
<div class="show-more{{#if messages.length}} show{{/if}}">
|
||||
<button class="show-more-button" data-id="{{id}}">Show older messages</button>
|
||||
<div class="chat-content">
|
||||
<div class="chat">
|
||||
<div class="show-more{{#if messages.length}} show{{/if}}">
|
||||
<button class="show-more-button" data-id="{{id}}">Show older messages</button>
|
||||
</div>
|
||||
<div class="messages" role="log" aria-live="polite" aria-relevant="additions"></div>
|
||||
</div>
|
||||
<div class="messages" role="log" aria-live="polite" aria-relevant="additions"></div>
|
||||
</div>
|
||||
{{#equal type "channel"}}
|
||||
<aside class="sidebar">
|
||||
<div class="users">
|
||||
{{#equal type "channel"}}
|
||||
<aside class="userlist">
|
||||
<div class="count">
|
||||
<input type="search" class="search" aria-label="Search among the user list" tabindex="-1">
|
||||
</div>
|
||||
<div class="names names-filtered"></div>
|
||||
<div class="names names-original"></div>
|
||||
</div>
|
||||
</aside>
|
||||
{{/equal}}
|
||||
</aside>
|
||||
{{/equal}}
|
||||
</div>
|
||||
</div>
|
||||
{{/each}}
|
||||
|
Loading…
Reference in New Issue
Block a user