commit: efc6b6b703971acd9cff7bb452a1fad40b801f87
parent 2c76c46aa7aa72cf1894f11e7da3fc6e60caabfa
Author: Henry Jameson <me@hjkos.com>
Date: Wed, 17 Aug 2022 20:49:20 +0300
add "scroll to top" button to timelines and notifications
Diffstat:
4 files changed, 44 insertions(+), 3 deletions(-)
diff --git a/src/components/notifications/notifications.js b/src/components/notifications/notifications.js
@@ -10,10 +10,11 @@ import {
} from '../../services/notification_utils/notification_utils.js'
import FaviconService from '../../services/favicon_service/favicon_service.js'
import { library } from '@fortawesome/fontawesome-svg-core'
-import { faCircleNotch } from '@fortawesome/free-solid-svg-icons'
+import { faCircleNotch, faCircleUp } from '@fortawesome/free-solid-svg-icons'
library.add(
- faCircleNotch
+ faCircleNotch,
+ faCircleUp
)
const DEFAULT_SEEN_TO_DISPLAY_COUNT = 30
@@ -34,6 +35,7 @@ const Notifications = {
},
data () {
return {
+ showScrollTop: false,
bottomedOut: false,
// How many seen notifications to display in the list. The more there are,
// the heavier the page becomes. This count is increased when loading
@@ -90,8 +92,16 @@ const Notifications = {
notificationsToDisplay () {
return this.filteredNotifications.slice(0, this.unseenCount + this.seenToDisplayCount)
},
+ noSticky () { return this.$store.getters.mergedConfig.disableStickyHeaders },
...mapGetters(['unreadChatCount'])
},
+ mounted () {
+ this.scrollerRef = this.$refs.root.closest('.column.-scrollable')
+ this.scrollerRef.addEventListener('scroll', this.updateScrollPosition)
+ },
+ unmounted () {
+ this.scrollerRef.removeEventListener('scroll', this.updateScrollPosition)
+ },
watch: {
unseenCountTitle (count) {
if (count > 0) {
@@ -104,6 +114,14 @@ const Notifications = {
}
},
methods: {
+ scrollToTop () {
+ const scrollable = this.scrollerRef
+ scrollable.scrollTo({ top: this.$refs.root.offsetTop })
+ // this.$refs.root.scrollIntoView({ behavior: 'smooth', block: 'start' })
+ },
+ updateScrollPosition () {
+ this.showScrollTop = this.$refs.root.offsetTop < this.scrollerRef.scrollTop
+ },
markAsSeen () {
this.$store.dispatch('markNotificationsAsSeen')
this.seenToDisplayCount = DEFAULT_SEEN_TO_DISPLAY_COUNT
diff --git a/src/components/notifications/notifications.vue b/src/components/notifications/notifications.vue
@@ -6,6 +6,7 @@
<div
:class="{ minimal: minimalMode }"
class="Notifications"
+ ref="root"
>
<div :class="mainClass">
<div
@@ -20,11 +21,20 @@
>{{ unseenCount }}</span>
</div>
<button
+ v-if="showScrollTop"
+ class="button-unstyled scroll-to-top-button"
+ type="button"
+ @click="scrollToTop"
+ >
+ <FAIcon icon="circle-up" />
+ </button>
+ <button
v-if="unseenCount"
class="button-default read-button"
+ type="button"
@click.prevent="markAsSeen"
>
- {{ $t('notifications.read') }}
+ <FAIcon icon="filter" />
</button>
<NotificationFilters />
</div>
diff --git a/src/components/timeline/timeline.js b/src/components/timeline/timeline.js
@@ -29,6 +29,7 @@ const Timeline = {
],
data () {
return {
+ showScrollTop: false,
paused: false,
unfocused: false,
bottomedOut: false,
@@ -123,6 +124,9 @@ const Timeline = {
this.$store.commit('setLoading', { timeline: this.timelineName, value: false })
},
methods: {
+ scrollToTop () {
+ window.scrollTo({ top: this.$el.offsetTop })
+ },
stopBlockingClicks: debounce(function () {
this.blockingClicks = false
}, 1000),
@@ -222,6 +226,7 @@ const Timeline = {
}
},
handleScroll: throttle(function (e) {
+ this.showScrollTop = this.$el.offsetTop < window.scrollY
this.determineVisibleStatuses()
this.scrollLoad(e)
}, 200),
diff --git a/src/components/timeline/timeline.vue b/src/components/timeline/timeline.vue
@@ -3,6 +3,14 @@
<div :class="classes.header">
<TimelineMenu v-if="!embedded" />
<button
+ v-if="showScrollTop"
+ class="button-unstyled scroll-to-top-button"
+ type="button"
+ @click="scrollToTop"
+ >
+ <FAIcon icon="circle-up" />
+ </button>
+ <button
v-if="showLoadButton"
class="button-default loadmore-button"
@click.prevent="showNewStatuses"