Page MenuHomePhorge

No OneTemporary

Size
11 KB
Referenced Files
None
Subscribers
None
diff --git a/src/components/mobile_nav/mobile_nav.js b/src/components/mobile_nav/mobile_nav.js
index 41cc4f457a..b47376d53d 100644
--- a/src/components/mobile_nav/mobile_nav.js
+++ b/src/components/mobile_nav/mobile_nav.js
@@ -1,169 +1,166 @@
import { mapState } from 'pinia'
import { defineAsyncComponent } from 'vue'
import { mapGetters } from 'vuex'
import NavigationPins from 'src/components/navigation/navigation_pins.vue'
import GestureService from '../../services/gesture_service/gesture_service'
import {
countExtraNotifications,
unseenNotificationsFromStore,
} from '../../services/notification_utils/notification_utils'
import { useAnnouncementsStore } from 'src/stores/announcements.js'
import { useInstanceStore } from 'src/stores/instance.js'
import { useMergedConfigStore } from 'src/stores/merged_config.js'
import { library } from '@fortawesome/fontawesome-svg-core'
import {
faArrowUp,
faBars,
faBell,
faCheckDouble,
faMinus,
faTimes,
} from '@fortawesome/free-solid-svg-icons'
library.add(faTimes, faBell, faBars, faArrowUp, faMinus, faCheckDouble)
const MobileNav = {
components: {
SideDrawer: defineAsyncComponent(
() => import('src/components/side_drawer/side_drawer.vue'),
),
Notifications: defineAsyncComponent(
() => import('src/components/notifications/notifications.vue'),
),
NavigationPins,
ConfirmModal: defineAsyncComponent(
() => import('src/components/confirm_modal/confirm_modal.vue'),
),
},
data: () => ({
notificationsCloseGesture: undefined,
notificationsOpen: false,
notificationsAtTop: true,
showingConfirmLogout: false,
}),
created() {
this.notificationsCloseGesture = GestureService.swipeGesture(
GestureService.DIRECTION_RIGHT,
() => this.closeMobileNotifications(true),
50,
)
},
computed: {
currentUser() {
return this.$store.state.users.currentUser
},
unseenNotifications() {
return unseenNotificationsFromStore(
this.$store,
useMergedConfigStore().mergedConfig.notificationVisibility,
useMergedConfigStore().mergedConfig.ignoreInactionableSeen,
)
},
unseenNotificationsCount() {
return (
this.unseenNotifications.length +
countExtraNotifications(
this.$store,
useMergedConfigStore().mergedConfig,
useAnnouncementsStore().unreadAnnouncementCount,
)
)
},
unseenCount() {
return this.unseenNotifications.length
},
unseenCountBadgeText() {
return `${this.unseenCount ? this.unseenCount : ''}`
},
hideSitename() {
return useInstanceStore().hideSitename
},
sitename() {
return useInstanceStore().name
},
isChat() {
return this.$route.name === 'chat'
},
...mapState(useAnnouncementsStore, ['unreadAnnouncementCount']),
...mapState(useMergedConfigStore, {
pinnedItems: (store) =>
new Set(store.prefsStorage.collections.pinnedNavItems).has('chats'),
}),
shouldConfirmLogout() {
return useMergedConfigStore().mergedConfig.modalOnLogout
},
closingDrawerMarksAsSeen() {
return useMergedConfigStore().mergedConfig.closingDrawerMarksAsSeen
},
...mapGetters(['unreadChatCount']),
},
methods: {
toggleMobileSidebar() {
this.$refs.sideDrawer.toggleDrawer()
},
openMobileNotifications() {
this.notificationsOpen = true
},
closeMobileNotifications(markRead) {
if (this.notificationsOpen) {
// make sure to mark notifs seen only when the notifs were open and not
// from close-calls.
this.notificationsOpen = false
if (markRead && this.closingDrawerMarksAsSeen) {
this.markNotificationsAsSeen()
}
}
},
notificationsTouchStart(e) {
GestureService.beginSwipe(e, this.notificationsCloseGesture)
},
notificationsTouchMove(e) {
GestureService.updateSwipe(e, this.notificationsCloseGesture)
},
scrollToTop() {
window.scrollTo(0, 0)
},
scrollMobileNotificationsToTop() {
this.$refs.mobileNotifications.scrollTo(0, 0)
},
showConfirmLogout() {
this.showingConfirmLogout = true
},
hideConfirmLogout() {
this.showingConfirmLogout = false
},
logout() {
if (!this.shouldConfirmLogout) {
this.doLogout()
} else {
this.showConfirmLogout()
}
},
doLogout() {
this.$router.replace('/main/public')
this.$store.dispatch('logout')
this.hideConfirmLogout()
},
markNotificationsAsSeen() {
this.$store.dispatch('markNotificationsAsSeen')
},
onScroll({ target: { scrollTop, clientHeight, scrollHeight } }) {
this.notificationsAtTop = scrollTop > 0
- if (scrollTop + clientHeight >= scrollHeight) {
- this.$refs.notifications.fetchOlderNotifications()
- }
},
},
watch: {
$route() {
// handles closing notificaitons when you press any router-link on the
// notifications.
this.closeMobileNotifications()
},
},
}
export default MobileNav
diff --git a/src/components/mobile_nav/mobile_nav.vue b/src/components/mobile_nav/mobile_nav.vue
index 09009782aa..743b7deb0b 100644
--- a/src/components/mobile_nav/mobile_nav.vue
+++ b/src/components/mobile_nav/mobile_nav.vue
@@ -1,259 +1,260 @@
<template>
<div
class="MobileNav"
>
<nav
id="nav"
class="mobile-nav"
@click="scrollToTop()"
>
<div class="item">
<button
class="button-unstyled mobile-nav-button"
:title="$t('nav.mobile_sidebar')"
:aria-expanaded="$refs.sideDrawer && !$refs.sideDrawer.closed"
@click.stop.prevent="toggleMobileSidebar()"
>
<FAIcon
class="fa-scale-110 fa-old-padding"
icon="bars"
/>
<div
v-if="(unreadChatCount && !chatsPinned) || unreadAnnouncementCount"
class="badge -dot -notification"
/>
</button>
<NavigationPins class="pins" />
</div> <div class="item right">
<button
v-if="currentUser"
class="button-unstyled mobile-nav-button"
:title="unseenNotificationsCount ? $t('nav.mobile_notifications_unread_active') : $t('nav.mobile_notifications')"
@click.stop.prevent="openMobileNotifications()"
>
<FAIcon
class="fa-scale-110 fa-old-padding"
icon="bell"
/>
<div
v-if="unseenNotificationsCount"
class="badge -dot -notification"
/>
</button>
</div>
</nav>
<aside
v-if="currentUser"
class="mobile-notifications-drawer mobile-drawer"
:class="{ '-closed': !notificationsOpen }"
@touchstart.stop="notificationsTouchStart"
@touchmove.stop="notificationsTouchMove"
>
<div class="panel-heading mobile-notifications-header">
<h1 class="title">
{{ $t('notifications.notifications') }}
<span
v-if="unseenCountBadgeText"
class="badge -notification unseen-count"
>{{ unseenCountBadgeText }}</span>
</h1>
<span class="spacer" />
<button
v-if="notificationsAtTop"
class="button-unstyled mobile-nav-button"
:title="$t('general.scroll_to_top')"
@click.stop.prevent="scrollMobileNotificationsToTop"
>
<FALayers class="fa-scale-110 fa-old-padding-layer">
<FAIcon icon="arrow-up" />
<FAIcon
icon="minus"
transform="up-7"
/>
</FALayers>
</button>
<button
v-if="!closingDrawerMarksAsSeen"
class="button-unstyled mobile-nav-button"
:title="$t('nav.mobile_notifications_mark_as_seen')"
@click.stop.prevent="markNotificationsAsSeen()"
>
<FAIcon
class="fa-scale-110 fa-old-padding"
icon="check-double"
/>
</button>
<button
class="button-unstyled mobile-nav-button"
:title="$t('nav.mobile_notifications_close')"
@click.stop.prevent="closeMobileNotifications(true)"
>
<FAIcon
class="fa-scale-110 fa-old-padding"
icon="times"
/>
</button>
</div>
+ <!-- Notifications teleport target -->
<div
id="mobile-notifications"
ref="mobileNotifications"
class="mobile-notifications"
@scroll="onScroll"
/>
</aside>
<SideDrawer
ref="sideDrawer"
:logout="logout"
/>
<teleport to="#modal">
<ConfirmModal
v-if="showingConfirmLogout"
:title="$t('login.logout_confirm_title')"
:confirm-danger="true"
:confirm-text="$t('login.logout_confirm_accept_button')"
:cancel-text="$t('login.logout_confirm_cancel_button')"
@accepted="doLogout"
@cancelled="hideConfirmLogout"
>
{{ $t('login.logout_confirm') }}
</ConfirmModal>
</teleport>
</div>
</template>
<script src="./mobile_nav.js"></script>
<style lang="scss">
.MobileNav {
z-index: var(--ZI_navbar);
.mobile-nav {
display: grid;
line-height: var(--navbar-height);
grid-template-rows: var(--navbar-height);
grid-template-columns: 2fr auto;
width: 100%;
box-sizing: border-box;
a {
color: var(--link);
}
}
.mobile-inner-nav {
width: 100%;
display: flex;
align-items: center;
}
.mobile-nav-button {
display: inline-block;
text-align: center;
padding: 0 1em;
position: relative;
cursor: pointer;
}
.site-name {
padding: 0 0.3em;
display: inline-block;
}
.item {
/* moslty just to get rid of extra whitespaces */
display: flex;
}
.mobile-notifications-drawer {
width: 100%;
height: 100vh;
overflow-x: hidden;
position: fixed;
top: 0;
left: 0;
box-shadow: var(--shadow);
transition-property: transform;
transition-duration: 0.25s;
transform: translateX(0);
z-index: var(--ZI_navbar);
-webkit-overflow-scrolling: touch;
background: var(--background);
&.-closed {
transform: translateX(100%);
box-shadow: none;
}
}
.mobile-notifications-header {
display: flex;
align-items: center;
justify-content: space-between;
z-index: calc(var(--ZI_navbar) + 100);
width: 100%;
height: 3.5em;
line-height: 3.5em;
position: absolute;
box-shadow: var(--shadow);
.spacer {
flex: 1;
}
.title {
font-size: 1.3em;
margin-left: 0.6em;
white-space: nowrap;
overflow-x: hidden;
text-overflow: ellipsis;
}
}
.pins {
flex: 1;
.pinned-item {
flex-grow: 1;
}
}
.mobile-notifications {
margin-top: 3.5em;
width: 100vw;
height: calc(100vh - var(--navbar-height));
overflow: hidden scroll;
.notifications {
padding: 0;
border-radius: 0;
box-shadow: none;
.panel {
border-radius: 0;
margin: 0;
box-shadow: none;
}
.panel::after {
border-radius: 0;
}
.panel .panel-heading {
border-radius: 0;
box-shadow: none;
}
}
}
.confirm-modal.dark-overlay {
&::before {
z-index: 3000;
}
.dialog-modal.panel {
z-index: 3001;
}
}
}
</style>

File Metadata

Mime Type
text/x-diff
Expires
Sat, Jul 18, 11:28 PM (1 d, 9 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
1695162
Default Alt Text
(11 KB)

Event Timeline