aboutsummaryrefslogtreecommitdiffstats
path: root/apps
diff options
context:
space:
mode:
authorGrigorii K. Shartsev <me@shgk.me>2024-01-30 14:40:14 +0100
committerGrigorii K. Shartsev <me@shgk.me>2024-02-08 01:05:06 +0100
commit66ba4c1e1bd681e807d7b549142c0e40433fe0c8 (patch)
tree421728d2708f2801143802c308cfd77b3feb3f65 /apps
parent0395cd8716312441be9f1011a5aa12adac9555e4 (diff)
downloadnextcloud-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')
-rw-r--r--apps/files_sharing/src/components/SharingEntry.vue20
-rw-r--r--apps/files_sharing/src/components/SharingEntryLink.vue14
-rw-r--r--apps/files_sharing/src/components/SharingEntryQuickShareSelect.vue261
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>