diff options
author | Grigorii K. Shartsev <me@shgk.me> | 2024-01-30 14:40:14 +0100 |
---|---|---|
committer | Grigorii K. Shartsev <me@shgk.me> | 2024-02-08 01:05:06 +0100 |
commit | 66ba4c1e1bd681e807d7b549142c0e40433fe0c8 (patch) | |
tree | 421728d2708f2801143802c308cfd77b3feb3f65 /apps | |
parent | 0395cd8716312441be9f1011a5aa12adac9555e4 (diff) | |
download | nextcloud-server-66ba4c1e1bd681e807d7b549142c0e40433fe0c8.tar.gz nextcloud-server-66ba4c1e1bd681e807d7b549142c0e40433fe0c8.zip |
fix(sharing): migrate QuickShareSelect to NcActions
Signed-off-by: Grigorii K. Shartsev <me@shgk.me>
Diffstat (limited to 'apps')
3 files changed, 95 insertions, 200 deletions
diff --git a/apps/files_sharing/src/components/SharingEntry.vue b/apps/files_sharing/src/components/SharingEntry.vue index 84525fa2f0c..74bff87560a 100644 --- a/apps/files_sharing/src/components/SharingEntry.vue +++ b/apps/files_sharing/src/components/SharingEntry.vue @@ -29,7 +29,7 @@ :menu-position="'left'" :url="share.shareWithAvatar" /> - <div class="sharing-entry__summary" @click.prevent="toggleQuickShareSelect"> + <div class="sharing-entry__summary"> <component :is="share.shareWithLink ? 'a' : 'div'" :title="tooltip" :aria-label="tooltip" @@ -41,14 +41,13 @@ <small v-if="hasStatus && share.status.message">({{ share.status.message }})</small> </span> </component> - <QuickShareSelect :share="share" + <SharingEntryQuickShareSelect :share="share" :file-info="fileInfo" - :toggle="showDropdown" @open-sharing-details="openShareDetailsForCustomSettings(share)" /> </div> <NcButton class="sharing-entry__action" :aria-label="t('files_sharing', 'Open Sharing Details')" - type="tertiary-no-background" + type="tertiary" @click="openSharingDetails(share)"> <template #icon> <DotsHorizontalIcon :size="20" /> @@ -63,7 +62,7 @@ import NcSelect from '@nextcloud/vue/dist/Components/NcSelect.js' import NcAvatar from '@nextcloud/vue/dist/Components/NcAvatar.js' import DotsHorizontalIcon from 'vue-material-design-icons/DotsHorizontal.vue' -import QuickShareSelect from './SharingEntryQuickShareSelect.vue' +import SharingEntryQuickShareSelect from './SharingEntryQuickShareSelect.vue' import SharesMixin from '../mixins/SharesMixin.js' import ShareDetails from '../mixins/ShareDetails.js' @@ -76,16 +75,11 @@ export default { NcAvatar, DotsHorizontalIcon, NcSelect, - QuickShareSelect, + SharingEntryQuickShareSelect, }, mixins: [SharesMixin, ShareDetails], - data() { - return { - showDropdown: false, - } - }, computed: { title() { let title = this.share.shareWithDisplayName @@ -140,9 +134,6 @@ export default { onMenuClose() { this.onNoteSubmit() }, - toggleQuickShareSelect() { - this.showDropdown = !this.showDropdown - }, }, } </script> @@ -158,6 +149,7 @@ export default { display: flex; flex-direction: column; justify-content: center; + align-items: flex-start; flex: 1 0; min-width: 0; diff --git a/apps/files_sharing/src/components/SharingEntryLink.vue b/apps/files_sharing/src/components/SharingEntryLink.vue index d59f569dd0e..d9060881f15 100644 --- a/apps/files_sharing/src/components/SharingEntryLink.vue +++ b/apps/files_sharing/src/components/SharingEntryLink.vue @@ -27,17 +27,16 @@ class="sharing-entry__avatar" /> <div class="sharing-entry__summary"> - <div class="sharing-entry__desc" @click.prevent="toggleQuickShareSelect"> + <div class="sharing-entry__desc"> <span class="sharing-entry__title" :title="title"> {{ title }} </span> <p v-if="subtitle"> {{ subtitle }} </p> - <QuickShareSelect v-if="share && share.permissions !== undefined" + <SharingEntryQuickShareSelect v-if="share && share.permissions !== undefined" :share="share" :file-info="fileInfo" - :toggle="showDropdown" @open-sharing-details="openShareDetailsForCustomSettings(share)" /> </div> @@ -199,7 +198,7 @@ import NcAvatar from '@nextcloud/vue/dist/Components/NcAvatar.js' import Tune from 'vue-material-design-icons/Tune.vue' -import QuickShareSelect from './SharingEntryQuickShareSelect.vue' +import SharingEntryQuickShareSelect from './SharingEntryQuickShareSelect.vue' import ExternalShareAction from './ExternalShareAction.vue' import GeneratePassword from '../utils/GeneratePassword.js' @@ -220,7 +219,7 @@ export default { NcActionSeparator, NcAvatar, Tune, - QuickShareSelect, + SharingEntryQuickShareSelect, }, mixins: [SharesMixin, ShareDetails], @@ -238,7 +237,6 @@ export default { data() { return { - showDropdown: false, copySuccess: true, copied: false, @@ -730,10 +728,6 @@ export default { // YET. We can safely delete the share :) this.$emit('remove:share', this.share) }, - - toggleQuickShareSelect() { - this.showDropdown = !this.showDropdown - }, }, } </script> diff --git a/apps/files_sharing/src/components/SharingEntryQuickShareSelect.vue b/apps/files_sharing/src/components/SharingEntryQuickShareSelect.vue index 2bf30533b59..79302ec6fbe 100644 --- a/apps/files_sharing/src/components/SharingEntryQuickShareSelect.vue +++ b/apps/files_sharing/src/components/SharingEntryQuickShareSelect.vue @@ -1,32 +1,25 @@ <template> - <div ref="quickShareDropdownContainer" - :class="{ 'active': showDropdown, 'share-select': true }"> - <span :id="dropdownId" - class="trigger-text" - :aria-expanded="showDropdown" - :aria-haspopup="true" - aria-label="Quick share options dropdown" - @click="toggleDropdown"> - {{ selectedOption }} + <NcActions ref="quickShareActions" + class="share-select" + :menu-name="selectedOption" + :aria-label="ariaLabel" + type="tertiary-no-background" + force-name> + <template #icon> <DropdownIcon :size="15" /> - </span> - <div v-if="showDropdown" - ref="quickShareDropdown" - class="share-select-dropdown" - :aria-labelledby="dropdownId" - tabindex="0" - @keydown.down="handleArrowDown" - @keydown.up="handleArrowUp" - @keydown.esc="closeDropdown"> - <button v-for="option in options" - :key="option" - :class="{ 'dropdown-item': true, 'selected': option === selectedOption }" - :aria-selected="option === selectedOption" - @click="selectOption(option)"> - {{ option }} - </button> - </div> - </div> + </template> + <NcActionButton v-for="option in options" + :key="option.label" + type="radio" + :model-value="option.label === selectedOption" + close-after-click + @click="selectOption(option.label)"> + <template #icon> + <component :is="option.icon" /> + </template> + {{ option.label }} + </NcActionButton> + </NcActions> </template> <script> @@ -34,37 +27,48 @@ import DropdownIcon from 'vue-material-design-icons/TriangleSmallDown.vue' import SharesMixin from '../mixins/SharesMixin.js' import ShareDetails from '../mixins/ShareDetails.js' import ShareTypes from '../mixins/ShareTypes.js' +import NcActions from '@nextcloud/vue/dist/Components/NcActions.js' +import NcActionButton from '@nextcloud/vue/dist/Components/NcActionButton.js' +import IconEyeOutline from 'vue-material-design-icons/EyeOutline.vue' +import IconPencil from 'vue-material-design-icons/Pencil.vue' +import IconFileUpload from 'vue-material-design-icons/FileUpload.vue' +import IconTune from 'vue-material-design-icons/Tune.vue' import { BUNDLED_PERMISSIONS, ATOMIC_PERMISSIONS, } from '../lib/SharePermissionsToolBox.js' -import { createFocusTrap } from 'focus-trap' - export default { + name: 'SharingEntryQuickShareSelect', + components: { DropdownIcon, + NcActions, + NcActionButton, }, + mixins: [SharesMixin, ShareDetails, ShareTypes], + props: { share: { type: Object, required: true, }, - toggle: { - type: Boolean, - default: false, - }, }, + + emits: ['open-sharing-details'], + data() { return { selectedOption: '', - showDropdown: this.toggle, - focusTrap: null, } }, + computed: { + ariaLabel() { + return t('files_sharing', 'Quick share options, the current selected is "{selectedOption}"', { selectedOption: this.selectedOption }) + }, canViewText() { return t('files_sharing', 'View only') }, @@ -91,11 +95,23 @@ export default { }, options() { - const options = [this.canViewText, this.canEditText] + const options = [{ + label: this.canViewText, + icon: IconEyeOutline, + }, { + label: this.canEditText, + icon: IconPencil, + }] if (this.supportsFileDrop) { - options.push(this.fileDropText) + options.push({ + label: this.fileDropText, + icon: IconFileUpload, + }) } - options.push(this.customPermissionsText) + options.push({ + label: this.customPermissionsText, + icon: IconTune, + }) return options }, @@ -119,96 +135,23 @@ export default { return BUNDLED_PERMISSIONS.READ_ONLY } }, - dropdownId() { - // Generate a unique ID for ARIA attributes - return `dropdown-${Math.random().toString(36).substr(2, 9)}` - }, }, - watch: { - toggle(toggleValue) { - this.showDropdown = toggleValue - }, - }, - mounted() { - this.initializeComponent() - window.addEventListener('click', this.handleClickOutside) - }, - beforeDestroy() { - // Remove the global click event listener to prevent memory leaks - window.removeEventListener('click', this.handleClickOutside) + + created() { + this.selectedOption = this.preSelectedOption }, + methods: { - toggleDropdown() { - this.showDropdown = !this.showDropdown - if (this.showDropdown) { - this.$nextTick(() => { - this.useFocusTrap() - }) - } else { - this.clearFocusTrap() - } - }, - closeDropdown() { - this.clearFocusTrap() - this.showDropdown = false - }, - selectOption(option) { - this.selectedOption = option - if (option === this.customPermissionsText) { + selectOption(optionLabel) { + this.selectedOption = optionLabel + if (optionLabel === this.customPermissionsText) { this.$emit('open-sharing-details') } else { this.share.permissions = this.dropDownPermissionValue this.queueUpdate('permissions') + // TODO: Add a focus method to NcActions or configurable returnFocus enabling to NcActionButton with closeAfterClick + this.$refs.quickShareActions.$refs.menuButton.$el.focus() } - this.showDropdown = false - }, - initializeComponent() { - this.selectedOption = this.preSelectedOption - }, - handleClickOutside(event) { - const dropdownContainer = this.$refs.quickShareDropdownContainer - - if (dropdownContainer && !dropdownContainer.contains(event.target)) { - this.showDropdown = false - } - }, - useFocusTrap() { - // Create global stack if undefined - // Use in with trapStack to avoid conflicting traps - Object.assign(window, { _nc_focus_trap: window._nc_focus_trap || [] }) - const dropdownElement = this.$refs.quickShareDropdown - this.focusTrap = createFocusTrap(dropdownElement, { - allowOutsideClick: true, - trapStack: window._nc_focus_trap, - }) - - this.focusTrap.activate() - }, - clearFocusTrap() { - this.focusTrap?.deactivate() - this.focusTrap = null - }, - shiftFocusForward() { - const currentElement = document.activeElement - let nextElement = currentElement.nextElementSibling - if (!nextElement) { - nextElement = this.$refs.quickShareDropdown.firstElementChild - } - nextElement.focus() - }, - shiftFocusBackward() { - const currentElement = document.activeElement - let previousElement = currentElement.previousElementSibling - if (!previousElement) { - previousElement = this.$refs.quickShareDropdown.lastElementChild - } - previousElement.focus() - }, - handleArrowUp() { - this.shiftFocusBackward() - }, - handleArrowDown() { - this.shiftFocusForward() }, }, @@ -217,65 +160,31 @@ export default { <style lang="scss" scoped> .share-select { - position: relative; - cursor: pointer; - - .trigger-text { - display: flex; - flex-direction: row; - align-items: center; - font-size: 12.5px; - gap: 2px; - color: var(--color-primary-element); - } - - .share-select-dropdown { - position: absolute; - display: flex; - flex-direction: column; - top: 100%; - left: 0; - background-color: var(--color-main-background); - border-radius: 8px; - box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2); - border: 1px solid var(--color-border); - padding: 4px 0; - z-index: 1; - - .dropdown-item { - padding: 8px; - font-size: 12px; - background: none; - border: none; - border-radius: 0; - font: inherit; - cursor: pointer; - color: inherit; - outline: none; - width: 100%; - white-space: nowrap; - text-align: left; - - &:hover { - background-color: var(--color-background-dark); - } - - &.selected { - background-color: var(--color-background-dark); - } + display: block; + + // TODO: NcActions should have a slot for custom trigger button like NcPopover + // Overrider NcActionms button to make it small + :deep(.action-item__menutoggle) { + color: var(--color-primary-element) !important; + font-size: 12.5px !important; + height: auto !important; + min-height: auto !important; + + .button-vue__text { + font-weight: normal !important; } - } - /* Optional: Add a transition effect for smoother dropdown animation */ - .share-select-dropdown { - max-height: 0; - overflow: hidden; - transition: max-height 0.3s ease; - } + .button-vue__icon { + height: 24px !important; + min-height: 24px !important; + width: 24px !important; + min-width: 24px !important; + } - &.active .share-select-dropdown { - max-height: 200px; - /* Adjust the value to your desired height */ + .button-vue__wrapper { + // Emulate NcButton's alignment=center-reverse + flex-direction: row-reverse !important; + } } } </style> |