From ad0f638487c45ad2f79375e38220b051ada5dfae Mon Sep 17 00:00:00 2001 From: Pavel Djundik Date: Wed, 18 Jul 2018 21:31:51 +0300 Subject: [PATCH] Add jump-to-bottom arrow when scrolled up --- client/components/MessageList.vue | 41 ++++++++++++++++---- client/css/style.css | 60 ++++++++++++++++++++++++++++++ client/js/socket-events/init.js | 2 + client/js/socket-events/network.js | 2 + 4 files changed, 98 insertions(+), 7 deletions(-) diff --git a/client/components/MessageList.vue b/client/components/MessageList.vue index a42f2be1..7ca57ed0 100644 --- a/client/components/MessageList.vue +++ b/client/components/MessageList.vue @@ -55,6 +55,18 @@ @linkPreviewToggle="onLinkPreviewToggle"/> + + + @@ -125,10 +137,23 @@ export default { return condensed; }, + unreadMessages() { + let unread = 0; + + for (let id = this.condensedMessages.length - 1; id > 0; id--) { + if (this.channel.firstUnread >= this.condensedMessages[id].id) { + break; + } + + unread++; + } + + return unread; + }, }, watch: { "channel.id"() { - this.$set(this.channel, "scrolledToBottom", true); + this.channel.scrolledToBottom = true; }, "channel.messages"() { this.keepScrollPosition(); @@ -153,7 +178,7 @@ export default { } this.channel.scrolledToBottom = true; - this.$refs.chat.scrollTop = this.$refs.chat.scrollHeight; + this.jumpToBottom(); }); }, mounted() { @@ -261,7 +286,7 @@ export default { this.isWaitingForNextTick = true; this.$nextTick(() => { this.isWaitingForNextTick = false; - el.scrollTop = el.scrollHeight; + this.jumpToBottom(); }); }, handleScroll() { @@ -275,12 +300,14 @@ export default { }, handleResize() { // Keep message list scrolled to bottom on resize - const el = this.$refs.chat; - - if (el && this.channel.scrolledToBottom) { - el.scrollTop = el.scrollHeight; + if (this.channel.scrolledToBottom) { + this.jumpToBottom(); } }, + jumpToBottom() { + const el = this.$refs.chat; + el.scrollTop = el.scrollHeight; + }, }, }; diff --git a/client/css/style.css b/client/css/style.css index e1b5d44b..201d8f82 100644 --- a/client/css/style.css +++ b/client/css/style.css @@ -259,6 +259,7 @@ kbd { #chat .action .from::before, #chat .toggle-button::after, #chat .toggle-content .more-caret::before, +#chat .scroll-down-arrow::after, #version-checker::before, .context-menu-item::before, #help .website-link::before, @@ -1082,6 +1083,65 @@ background on hover (unless active) */ margin: 0; } +.scroll-down.fade-leave-active, +.scroll-down.fade-enter-active { + opacity: 0; + transform: translateY(16px); + transition: opacity .3s, transform .3s; +} + +.scroll-down.fade-enter-to { + opacity: 1; + transform: none; +} + +.scroll-down { + position: absolute; + + bottom: 16px; + right: 16px; + z-index: 2; + transition: right 0.2s ease-in-out; + cursor: pointer; +} + +.scroll-down-number { + background: #84ce88; + border-radius: 50%; + text-align: center; + width: 30px; + height: 30px; + line-height: 30px; + font-size: 12px; + margin-left: 9px; + z-index: 23; + position: absolute; + top: -20px; + font-weight: bold; +} + +.scroll-down-arrow { + width: 48px; + height: 48px; + line-height: 48px; + border-radius: 50%; + background: #fff; + border: 1px solid #84ce88; + text-align: center; +} + +.scroll-down:hover .scroll-down-arrow { + background: #84ce88; +} + +.scroll-down-arrow::after { + content: "\f107"; /* https://fontawesome.com/icons/angle-down?style=solid */ +} + +.userlist-open #chat .scroll-down { + right: 196px; +} + #chat .messages { padding: 10px 0; touch-action: pan-y; diff --git a/client/js/socket-events/init.js b/client/js/socket-events/init.js index 1e807700..2e9347ee 100644 --- a/client/js/socket-events/init.js +++ b/client/js/socket-events/init.js @@ -47,6 +47,8 @@ socket.on("init", function(data) { } for (const channel of network.channels) { + channel.scrolledToBottom = true; + if (channel.type === "channel") { channel.usersOutdated = true; } diff --git a/client/js/socket-events/network.js b/client/js/socket-events/network.js index e5c1d80c..67f19ba7 100644 --- a/client/js/socket-events/network.js +++ b/client/js/socket-events/network.js @@ -14,6 +14,8 @@ socket.on("network", function(data) { network.isCollapsed = false; for (const channel of network.channels) { + channel.scrolledToBottom = true; + if (channel.type === "channel") { channel.usersOutdated = true; }