diff options
author | Christopher Ng <chrng8@gmail.com> | 2023-01-12 01:35:53 +0000 |
---|---|---|
committer | Christopher Ng <chrng8@gmail.com> | 2023-01-13 23:19:28 +0000 |
commit | f6aa5224c4c8a1e9e57f0a8069bd5f70054314e8 (patch) | |
tree | df492c57c99bd6cfeea6d381faf1beb693cad89c /core/src | |
parent | f7ff54860bef10c856542bb17ceb90e824c62dc8 (diff) | |
download | nextcloud-server-f6aa5224c4c8a1e9e57f0a8069bd5f70054314e8.tar.gz nextcloud-server-f6aa5224c4c8a1e9e57f0a8069bd5f70054314e8.zip |
Focus trap contacts menu with NcHeaderMenu port
Signed-off-by: Christopher Ng <chrng8@gmail.com>
Signed-off-by: nextcloud-command <nextcloud-command@users.noreply.github.com>
Signed-off-by: Christopher Ng <chrng8@gmail.com>
Diffstat (limited to 'core/src')
-rw-r--r-- | core/src/OC/contactsmenu.js | 42 | ||||
-rw-r--r-- | core/src/components/ContactsMenu.js | 19 | ||||
-rw-r--r-- | core/src/views/ContactsMenu.vue | 198 |
3 files changed, 218 insertions, 41 deletions
diff --git a/core/src/OC/contactsmenu.js b/core/src/OC/contactsmenu.js index 7e1586aeead..b9f4b0fc064 100644 --- a/core/src/OC/contactsmenu.js +++ b/core/src/OC/contactsmenu.js @@ -381,8 +381,7 @@ const ContactsMenuView = View.extend({ /** * @param {Object} options - * @param {jQuery} options.el - * @param {jQuery} options.trigger + * @param {string} options.el * @class ContactsMenu * @memberOf OC */ @@ -391,12 +390,9 @@ const ContactsMenu = function(options) { } ContactsMenu.prototype = { - /** @type {jQuery} */ + /** @type {string} */ $el: undefined, - /** @type {jQuery} */ - _$trigger: undefined, - /** @type {ContactsMenuView} */ _view: undefined, @@ -405,41 +401,19 @@ ContactsMenu.prototype = { /** * @param {Object} options - * @param {jQuery} options.el - the element to render the menu in - * @param {jQuery} options.trigger - the element to click on to open the menu + * @param {string} options.el - the selector of the element to render the menu in * @returns {undefined} */ initialize: function(options) { - this.$el = options.el - this._$trigger = options.trigger + this.$el = $(options.el) this._view = new ContactsMenuView({ - el: this.$el + el: this.$el, }) + this._view.on('search', function(searchTerm) { - this._loadContacts(searchTerm) + this.loadContacts(searchTerm) }, this) - - OC.registerMenu(this._$trigger, this.$el, function() { - this._toggleVisibility(true) - }.bind(this), true) - this.$el.on('beforeHide', function() { - this._toggleVisibility(false) - }.bind(this)) - }, - - /** - * @private - * @param {boolean} show - * @returns {Promise} - */ - _toggleVisibility: function(show) { - if (show) { - return this._loadContacts() - } else { - this.$el.html('') - return Promise.resolve() - } }, /** @@ -461,7 +435,7 @@ ContactsMenu.prototype = { * @param {string|undefined} searchTerm * @returns {undefined} */ - _loadContacts: function(searchTerm) { + loadContacts: function(searchTerm) { var self = this if (!self._contactsPromise) { diff --git a/core/src/components/ContactsMenu.js b/core/src/components/ContactsMenu.js index cf031331a50..1b7b25873d0 100644 --- a/core/src/components/ContactsMenu.js +++ b/core/src/components/ContactsMenu.js @@ -2,6 +2,7 @@ * @copyright 2019 Christoph Wurst <christoph@winzerhof-wurst.at> * * @author Christoph Wurst <christoph@winzerhof-wurst.at> + * @author Christopher Ng <chrng8@gmail.com> * @author John Molakvoæ <skjnldsv@protonmail.com> * * @license AGPL-3.0-or-later @@ -21,16 +22,20 @@ * */ -import $ from 'jquery' -import OC from '../OC' +import Vue from 'vue' + +import ContactsMenu from '../views/ContactsMenu.vue' /** * @todo move to contacts menu code https://github.com/orgs/nextcloud/projects/31#card-21213129 */ export const setUp = () => { - // eslint-disable-next-line no-new - new OC.ContactsMenu({ - el: $('#contactsmenu .menu'), - trigger: $('#contactsmenu .menutoggle'), - }) + const mountPoint = document.getElementById('contactsmenu') + if (mountPoint) { + // eslint-disable-next-line no-new + new Vue({ + el: mountPoint, + render: h => h(ContactsMenu), + }) + } } diff --git a/core/src/views/ContactsMenu.vue b/core/src/views/ContactsMenu.vue new file mode 100644 index 00000000000..f03652bb477 --- /dev/null +++ b/core/src/views/ContactsMenu.vue @@ -0,0 +1,198 @@ +<!-- + - @copyright 2023 Christopher Ng <chrng8@gmail.com> + - + - @author Christopher Ng <chrng8@gmail.com> + - + - @license AGPL-3.0-or-later + - + - This program is free software: you can redistribute it and/or modify + - it under the terms of the GNU Affero General Public License as + - published by the Free Software Foundation, either version 3 of the + - License, or (at your option) any later version. + - + - This program is distributed in the hope that it will be useful, + - but WITHOUT ANY WARRANTY; without even the implied warranty of + - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + - GNU Affero General Public License for more details. + - + - You should have received a copy of the GNU Affero General Public License + - along with this program. If not, see <http://www.gnu.org/licenses/>. + - +--> + +<template> + <NcHeaderMenu id="contactsmenu" + :aria-label="t('core', 'Search contacts')" + @open="handleOpen"> + <template #trigger> + <Contacts :size="20" /> + </template> + <div id="contactsmenu-menu" /> + </NcHeaderMenu> +</template> + +<script> +import NcHeaderMenu from '@nextcloud/vue/dist/Components/NcHeaderMenu.js' + +import Contacts from 'vue-material-design-icons/Contacts.vue' + +import OC from '../OC/index.js' + +export default { + name: 'ContactsMenu', + + components: { + Contacts, + NcHeaderMenu, + }, + + data() { + return { + contactsMenu: null, + } + }, + + mounted() { + // eslint-disable-next-line no-new + this.contactsMenu = new OC.ContactsMenu({ + el: '#contactsmenu-menu', + }) + }, + + methods: { + handleOpen() { + this.contactsMenu?.loadContacts() + }, + }, +} +</script> + +<style lang="scss" scoped> +#contactsmenu-menu { + /* show 2.5 to 4.5 entries depending on the screen height */ + height: calc(100vh - 50px * 3); + max-height: calc(50px * 6 + 2px); + min-height: calc(50px * 3.5); + width: 350px; + + &:deep { + .emptycontent { + margin-top: 5vh !important; + margin-bottom: 1.5vh; + .icon-loading, + .icon-search { + display: inline-block; + } + } + + #contactsmenu-search { + width: calc(100% - 16px); + margin: 8px; + height: 34px; + } + + .content { + /* fixed max height of the parent container without the search input */ + height: calc(100vh - 50px * 3 - 50px); + max-height: calc(50px * 5); + min-height: calc(50px * 3.5 - 50px); + overflow-y: auto; + + .footer { + text-align: center; + + a { + display: block; + width: 100%; + padding: 12px 0; + opacity: .5; + } + } + } + + a { + padding: 2px; + + &:focus-visible { + box-shadow: inset 0 0 0 2px var(--color-main-text) !important; // override rule in core/css/headers.scss #header a:focus-visible + } + } + + .contact { + display: flex; + position: relative; + align-items: center; + padding: 3px 3px 3px 10px; + + .avatar { + height: 32px; + width: 32px; + display: inline-block; + } + + .body { + flex-grow: 1; + padding-left: 8px; + + div { + position: relative; + width: 100%; + } + + .full-name, .last-message { + /* TODO: don't use fixed width */ + max-width: 204px; + overflow: hidden; + white-space: nowrap; + text-overflow: ellipsis; + } + .last-message, .email-address { + color: var(--color-text-maxcontrast); + } + } + + .top-action, .second-action, .other-actions { + width: 16px; + height: 16px; + opacity: .5; + cursor: pointer; + + &:not(button) { + padding: 14px; + } + img { + filter: var(--background-invert-if-dark); + } + + &:hover, + &:active, + &:focus { + opacity: 1; + } + } + + button.other-actions { + width: 44px; + + &:focus { + border-color: transparent; + box-shadow: 0 0 0 2px var(--color-main-text); + } + + &:focus-visible { + border-radius: var(--border-radius-pill); + } + } + + /* actions menu */ + .menu { + top: 47px; + margin-right: 13px; + } + .popovermenu::after { + right: 2px; + } + } + } +} +</style> |