зеркало из https://github.com/nextcloud/spreed.git
Merge pull request #12693 from nextcloud/backport/12610/stable28
[stable28] fix(sidebar): use open state to remove always working focus trap on mobile
This commit is contained in:
Коммит
f471eca3d5
|
@ -21,14 +21,33 @@
|
|||
-->
|
||||
|
||||
<template>
|
||||
<NcAppSidebar v-show="opened"
|
||||
<NcAppSidebar v-if="token"
|
||||
:open="opened"
|
||||
:name="name"
|
||||
:title="name"
|
||||
:active="activeTab"
|
||||
:class="'active-tab-' + activeTab"
|
||||
:toggle-classes="{ 'chat-button-sidebar-toggle': isInCall }"
|
||||
:toggle-attrs="isInCall ? inCallToggleAttrs : undefined"
|
||||
@update:open="handleUpdateOpen"
|
||||
@update:active="handleUpdateActive"
|
||||
@closed="handleClosed"
|
||||
@close="handleClose">
|
||||
<!-- Use a custom icon when sidebar is used for chat messages during the call -->
|
||||
<template #toggle-icon>
|
||||
<template v-if="isInCall">
|
||||
<MessageText :size="20" />
|
||||
<NcCounterBubble v-if="unreadMessagesCounter > 0"
|
||||
class="chat-button__unread-messages-counter"
|
||||
:type="hasUnreadMentions ? 'highlighted' : 'outlined'">
|
||||
{{ unreadMessagesCounter }}
|
||||
</NcCounterBubble>
|
||||
</template>
|
||||
<template v-else>
|
||||
<!-- Use the old icon on older versions -->
|
||||
<MenuIcon :size="20" />
|
||||
</template>
|
||||
</template>
|
||||
<template #description>
|
||||
<LobbyStatus v-if="canFullModerate && hasLobbyEnabled" :token="token" />
|
||||
</template>
|
||||
|
@ -106,13 +125,17 @@ import CogIcon from 'vue-material-design-icons/Cog.vue'
|
|||
import DotsCircle from 'vue-material-design-icons/DotsCircle.vue'
|
||||
import FolderMultipleImage from 'vue-material-design-icons/FolderMultipleImage.vue'
|
||||
import InformationOutline from 'vue-material-design-icons/InformationOutline.vue'
|
||||
import MenuIcon from 'vue-material-design-icons/Menu.vue'
|
||||
import Message from 'vue-material-design-icons/Message.vue'
|
||||
import MessageText from 'vue-material-design-icons/MessageText.vue'
|
||||
|
||||
import { showMessage } from '@nextcloud/dialogs'
|
||||
import { emit, subscribe, unsubscribe } from '@nextcloud/event-bus'
|
||||
|
||||
import NcAppSidebar from '@nextcloud/vue/dist/Components/NcAppSidebar.js'
|
||||
import NcAppSidebarTab from '@nextcloud/vue/dist/Components/NcAppSidebarTab.js'
|
||||
import NcButton from '@nextcloud/vue/dist/Components/NcButton.js'
|
||||
import NcCounterBubble from '@nextcloud/vue/dist/Components/NcCounterBubble.js'
|
||||
|
||||
import BreakoutRoomsTab from './BreakoutRooms/BreakoutRoomsTab.vue'
|
||||
import LobbyStatus from './LobbyStatus.vue'
|
||||
|
@ -135,6 +158,7 @@ export default {
|
|||
NcAppSidebar,
|
||||
NcAppSidebarTab,
|
||||
NcButton,
|
||||
NcCounterBubble,
|
||||
ParticipantsTab,
|
||||
SetGuestUsername,
|
||||
SharedItemsTab,
|
||||
|
@ -146,6 +170,8 @@ export default {
|
|||
FolderMultipleImage,
|
||||
InformationOutline,
|
||||
Message,
|
||||
MessageText,
|
||||
MenuIcon,
|
||||
},
|
||||
|
||||
mixins: [
|
||||
|
@ -163,6 +189,7 @@ export default {
|
|||
return {
|
||||
activeTab: 'participants',
|
||||
contactsLoading: false,
|
||||
unreadNotificationHandle: null,
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -171,7 +198,7 @@ export default {
|
|||
return this.$store.getters.getSidebarStatus
|
||||
},
|
||||
opened() {
|
||||
return !!this.token && !this.isInLobby && this.show
|
||||
return !this.isInLobby && this.show
|
||||
},
|
||||
token() {
|
||||
return this.$store.getters.getToken()
|
||||
|
@ -277,6 +304,21 @@ export default {
|
|||
breakoutRoomsText() {
|
||||
return t('spreed', 'Breakout rooms')
|
||||
},
|
||||
|
||||
unreadMessagesCounter() {
|
||||
return this.conversation.unreadMessages
|
||||
},
|
||||
hasUnreadMentions() {
|
||||
return this.conversation.unreadMention
|
||||
},
|
||||
|
||||
inCallToggleAttrs() {
|
||||
return {
|
||||
'data-theme-dark': true,
|
||||
'aria-label': t('spreed', 'Open chat'),
|
||||
title: t('spreed', 'Open chat')
|
||||
}
|
||||
},
|
||||
},
|
||||
|
||||
watch: {
|
||||
|
@ -311,6 +353,27 @@ export default {
|
|||
},
|
||||
},
|
||||
|
||||
unreadMessagesCounter(newValue, oldValue) {
|
||||
if (!this.isInCall || this.opened) {
|
||||
return
|
||||
}
|
||||
|
||||
// new messages arrived
|
||||
if (newValue > 0 && oldValue === 0 && !this.hasUnreadMentions) {
|
||||
this.notifyUnreadMessages(t('spreed', 'You have new unread messages in the chat.'))
|
||||
}
|
||||
},
|
||||
|
||||
hasUnreadMentions(newValue) {
|
||||
if (!this.isInCall || this.opened) {
|
||||
return
|
||||
}
|
||||
|
||||
if (newValue) {
|
||||
this.notifyUnreadMessages(t('spreed', 'You have been mentioned in the chat.'))
|
||||
}
|
||||
},
|
||||
|
||||
isInCall(newValue) {
|
||||
if (newValue) {
|
||||
// Set 'chat' tab as active, and switch to it if sidebar is open
|
||||
|
@ -318,6 +381,9 @@ export default {
|
|||
return
|
||||
}
|
||||
|
||||
// discard notification if the call ends
|
||||
this.notifyUnreadMessages(null)
|
||||
|
||||
// If 'chat' tab wasn't active, leave it as is
|
||||
if (this.activeTab !== 'chat') {
|
||||
return
|
||||
|
@ -358,11 +424,28 @@ export default {
|
|||
},
|
||||
|
||||
methods: {
|
||||
openSidebar() {
|
||||
// In call by default open on chat
|
||||
if (this.isInCall) {
|
||||
this.activeTab = 'chat'
|
||||
}
|
||||
this.$store.dispatch('showSidebar')
|
||||
BrowserStorage.setItem('sidebarOpen', 'true')
|
||||
},
|
||||
|
||||
handleClose() {
|
||||
this.$store.dispatch('hideSidebar')
|
||||
BrowserStorage.setItem('sidebarOpen', 'false')
|
||||
},
|
||||
|
||||
handleUpdateOpen(open) {
|
||||
if (open) {
|
||||
this.openSidebar()
|
||||
} else {
|
||||
this.handleClose()
|
||||
}
|
||||
},
|
||||
|
||||
handleUpdateActive(active) {
|
||||
this.activeTab = active
|
||||
},
|
||||
|
@ -374,6 +457,21 @@ export default {
|
|||
handleClosed() {
|
||||
emit('files:sidebar:closed', {})
|
||||
},
|
||||
|
||||
notifyUnreadMessages(message) {
|
||||
if (this.unreadNotificationHandle) {
|
||||
this.unreadNotificationHandle.hideToast()
|
||||
this.unreadNotificationHandle = null
|
||||
}
|
||||
if (message) {
|
||||
this.unreadNotificationHandle = showMessage(message, {
|
||||
onClick: () => {
|
||||
this.activeTab = 'chat'
|
||||
this.openSidebar()
|
||||
},
|
||||
})
|
||||
}
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
@ -414,4 +512,26 @@ export default {
|
|||
height: 100%;
|
||||
}
|
||||
|
||||
.chat-button__unread-messages-counter {
|
||||
position: absolute;
|
||||
bottom: 2px;
|
||||
right: 2px;
|
||||
pointer-events: none;
|
||||
|
||||
&.counter-bubble__counter--highlighted {
|
||||
color: var(--color-primary-text);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
<style lang="scss">
|
||||
/*
|
||||
* NcAppSidebar toggle it rendered on the page outside the sidebar element, so we need global styles here.
|
||||
* It is _quite_ safe, as chat-button-sidebar-toggle class is defined here manually, not an internal class.
|
||||
*/
|
||||
.chat-button-sidebar-toggle {
|
||||
position: relative;
|
||||
// Allow unread counter to overflow rounded button
|
||||
overflow: visible !important;
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -100,40 +100,6 @@
|
|||
|
||||
<CallButton class="top-bar__button" />
|
||||
|
||||
<!-- sidebar toggle -->
|
||||
<template v-if="showOpenSidebarButton">
|
||||
<!-- in chat: open last tab -->
|
||||
<NcButton v-if="!isInCall"
|
||||
:aria-label="t('spreed', 'Open sidebar')"
|
||||
:title="t('spreed', 'Open sidebar')"
|
||||
class="top-bar__button dark-hover"
|
||||
close-after-click="true"
|
||||
type="tertiary"
|
||||
@click="openSidebar">
|
||||
<template #icon>
|
||||
<MenuIcon :size="20" />
|
||||
</template>
|
||||
</NcButton>
|
||||
|
||||
<!-- in call: open chat tab -->
|
||||
<NcButton v-else
|
||||
:aria-label="t('spreed', 'Open chat')"
|
||||
:title="t('spreed', 'Open chat')"
|
||||
class="top-bar__button chat-button dark-hover"
|
||||
type="tertiary"
|
||||
@click="openSidebar('chat')">
|
||||
<template #icon>
|
||||
<MessageText :size="20"
|
||||
fill-color="#ffffff" />
|
||||
<NcCounterBubble v-if="unreadMessagesCounter > 0"
|
||||
class="chat-button__unread-messages-counter"
|
||||
:type="hasUnreadMentions ? 'highlighted' : 'outlined'">
|
||||
{{ unreadMessagesCounter }}
|
||||
</NcCounterBubble>
|
||||
</template>
|
||||
</NcButton>
|
||||
</template>
|
||||
|
||||
<!-- Breakout rooms editor -->
|
||||
<BreakoutRoomsEditor v-if="showBreakoutRoomsEditor"
|
||||
:token="token"
|
||||
|
@ -143,15 +109,11 @@
|
|||
|
||||
<script>
|
||||
import AccountMultiple from 'vue-material-design-icons/AccountMultiple.vue'
|
||||
import MenuIcon from 'vue-material-design-icons/Menu.vue'
|
||||
import MessageText from 'vue-material-design-icons/MessageText.vue'
|
||||
|
||||
import { getCapabilities } from '@nextcloud/capabilities'
|
||||
import { showMessage } from '@nextcloud/dialogs'
|
||||
import { emit } from '@nextcloud/event-bus'
|
||||
|
||||
import NcButton from '@nextcloud/vue/dist/Components/NcButton.js'
|
||||
import NcCounterBubble from '@nextcloud/vue/dist/Components/NcCounterBubble.js'
|
||||
import Tooltip from '@nextcloud/vue/dist/Directives/Tooltip.js'
|
||||
import richEditor from '@nextcloud/vue/dist/Mixins/richEditor.js'
|
||||
|
||||
|
@ -184,13 +146,10 @@ export default {
|
|||
ConversationIcon,
|
||||
TopBarMediaControls,
|
||||
NcButton,
|
||||
NcCounterBubble,
|
||||
TopBarMenu,
|
||||
ReactionMenu,
|
||||
// Icons
|
||||
AccountMultiple,
|
||||
MenuIcon,
|
||||
MessageText,
|
||||
},
|
||||
|
||||
mixins: [
|
||||
|
@ -215,7 +174,6 @@ export default {
|
|||
|
||||
data: () => {
|
||||
return {
|
||||
unreadNotificationHandle: null,
|
||||
showBreakoutRoomsEditor: false,
|
||||
localCallParticipantModel,
|
||||
localMediaModel,
|
||||
|
@ -227,10 +185,6 @@ export default {
|
|||
return this.$store.getters.getMainContainerSelector()
|
||||
},
|
||||
|
||||
showOpenSidebarButton() {
|
||||
return !this.$store.getters.getSidebarStatus
|
||||
},
|
||||
|
||||
isOneToOneConversation() {
|
||||
return this.conversation.type === CONVERSATION.TYPE.ONE_TO_ONE
|
||||
},
|
||||
|
@ -251,13 +205,6 @@ export default {
|
|||
return getStatusMessage(this.conversation)
|
||||
},
|
||||
|
||||
unreadMessagesCounter() {
|
||||
return this.conversation.unreadMessages
|
||||
},
|
||||
hasUnreadMentions() {
|
||||
return this.conversation.unreadMention
|
||||
},
|
||||
|
||||
renderedDescription() {
|
||||
return this.renderContent(this.conversation.description)
|
||||
},
|
||||
|
@ -314,34 +261,6 @@ export default {
|
|||
},
|
||||
|
||||
watch: {
|
||||
unreadMessagesCounter(newValue, oldValue) {
|
||||
if (!this.isInCall || !this.showOpenSidebarButton) {
|
||||
return
|
||||
}
|
||||
|
||||
// new messages arrived
|
||||
if (newValue > 0 && oldValue === 0 && !this.hasUnreadMentions) {
|
||||
this.notifyUnreadMessages(t('spreed', 'You have new unread messages in the chat.'))
|
||||
}
|
||||
},
|
||||
|
||||
hasUnreadMentions(newValue) {
|
||||
if (!this.isInCall || !this.showOpenSidebarButton) {
|
||||
return
|
||||
}
|
||||
|
||||
if (newValue) {
|
||||
this.notifyUnreadMessages(t('spreed', 'You have been mentioned in the chat.'))
|
||||
}
|
||||
},
|
||||
|
||||
isInCall(newValue) {
|
||||
if (!newValue) {
|
||||
// discard notification if the call ends
|
||||
this.notifyUnreadMessages(null)
|
||||
}
|
||||
},
|
||||
|
||||
isOneToOneConversation: {
|
||||
immediate: true,
|
||||
// Group conversations have mixin in RightSidebar, so should work only for one-to-one
|
||||
|
@ -373,16 +292,6 @@ export default {
|
|||
},
|
||||
|
||||
methods: {
|
||||
notifyUnreadMessages(message) {
|
||||
if (this.unreadNotificationHandle) {
|
||||
this.unreadNotificationHandle.hideToast()
|
||||
this.unreadNotificationHandle = null
|
||||
}
|
||||
if (message) {
|
||||
this.unreadNotificationHandle = showMessage(message)
|
||||
}
|
||||
},
|
||||
|
||||
openSidebar(activeTab) {
|
||||
if (typeof activeTab === 'string') {
|
||||
emit('spreed:select-active-sidebar-tab', activeTab)
|
||||
|
@ -410,7 +319,9 @@ export default {
|
|||
display: flex;
|
||||
z-index: 10;
|
||||
justify-content: flex-end;
|
||||
padding: 8px;
|
||||
padding: calc(2 * var(--default-grid-baseline));
|
||||
// Reserve space for the sidebar toggle button
|
||||
padding-right: calc(2 * var(--default-grid-baseline) + var(--app-sidebar-offset));
|
||||
background-color: var(--color-main-background);
|
||||
border-bottom: 1px solid var(--color-border);
|
||||
|
||||
|
@ -454,18 +365,6 @@ export default {
|
|||
}
|
||||
}
|
||||
|
||||
.chat-button {
|
||||
position: relative;
|
||||
overflow: visible;
|
||||
&__unread-messages-counter {
|
||||
position: absolute;
|
||||
top: 24px;
|
||||
right: 2px;
|
||||
pointer-events: none;
|
||||
color: var(--color-primary-element);
|
||||
}
|
||||
}
|
||||
|
||||
&--authorised {
|
||||
.conversation-icon {
|
||||
margin-left: calc(var(--default-clickable-area) + var(--default-grid-baseline));
|
||||
|
|
Загрузка…
Ссылка в новой задаче