- Mobile menu components refactoring

- Components name renaming
This commit is contained in:
Peter Papp
2021-04-14 11:17:29 +02:00
parent 16b7575fca
commit eba8903792
40 changed files with 1044 additions and 1340 deletions
@@ -1,16 +1,18 @@
<template>
<div v-if="isVisible" class="sorting-preview">
<SortingAndPreviewMenu />
<FileSortingOptions />
</div>
</template>
<script>
import SortingAndPreviewMenu from '@/components/FilesView/SortingAndPreviewMenu'
import FileSortingOptions from '@/components/FilesView/FileSortingOptions'
import { events } from '@/bus'
export default {
name: 'DesktopSortingAndPreview',
components: {SortingAndPreviewMenu},
name: 'DesktopSortingOptions',
components: {
FileSortingOptions
},
data () {
return {
isVisible: false
@@ -1,7 +1,7 @@
<template>
<div id="mobile-actions-wrapper">
<!--Actions for trash location with MASTER permission--->
<!--Actions for trash location--->
<div v-if="trashLocationMenu && ! multiSelectMode" class="mobile-actions">
<MobileActionButton @click.native="$store.dispatch('emptyTrash')" icon="trash">
{{ $t('context_menu.empty_trash') }}
@@ -9,25 +9,28 @@
<MobileActionButton @click.native="enableMultiSelectMode" icon="check-square">
{{ $t('context_menu.select') }}
</MobileActionButton>
<MobileActionButton class="preview-sorting" @click.native="showViewOptions" icon="preview-sorting">
{{$t('preview_sorting.preview_sorting_button')}}
<MobileActionButton @click.native="showViewOptions" icon="preview-sorting">
{{ $t('preview_sorting.preview_sorting_button') }}
</MobileActionButton>
</div>
<!--ContextMenu for Base location with MASTER permission-->
<!--Actions for Base location-->
<transition name="button">
<div v-if="baseLocationMasterMenu && ! multiSelectMode" class="mobile-actions">
<MobileActionButton @click.native="createFolder" icon="folder-plus" :class="{'is-inactive' : multiSelectMode}">
<MobileActionButton @click.native="showLocations" icon="filter">
{{ filterLocationTitle }}
</MobileActionButton>
<MobileActionButton @click.native="createFolder" icon="folder-plus">
{{ $t('context_menu.add_folder') }}
</MobileActionButton>
<MobileActionButtonUpload :class="{'is-inactive' : multiSelectMode}">
<MobileActionButtonUpload>
{{ $t('context_menu.upload') }}
</MobileActionButtonUpload>
<MobileActionButton @click.native="enableMultiSelectMode" icon="check-square">
{{ $t('context_menu.select') }}
</MobileActionButton>
<MobileActionButton class="preview-sorting" @click.native="showViewOptions" icon="preview-sorting">
{{$t('preview_sorting.preview_sorting_button')}}
<MobileActionButton @click.native="showViewOptions" icon="preview-sorting">
{{ $t('preview_sorting.preview_sorting_button') }}
</MobileActionButton>
</div>
</transition>
@@ -36,24 +39,24 @@
<transition name="button">
<div v-if="multiSelectMode" class="mobile-actions">
<MobileActionButton @click.native="selectAll" icon="check-square">
{{$t('mobile_selecting.select_all')}}
{{ $t('mobile_selecting.select_all') }}
</MobileActionButton>
<MobileActionButton @click.native="deselectAll" icon="x-square">
{{$t('mobile_selecting.deselect_all')}}
{{ $t('mobile_selecting.deselect_all') }}
</MobileActionButton>
<MobileActionButton @click.native="disableMultiSelectMode" icon="check">
{{$t('mobile_selecting.done')}}
{{ $t('mobile_selecting.done') }}
</MobileActionButton>
</div>
</transition>
<!--ContextMenu for Base location with VISITOR permission-->
<!--Actions for Base location in shared folder with visit permission-->
<div v-if="baseLocationVisitorMenu && ! multiSelectMode" class="mobile-actions">
<MobileActionButton @click.native="enableMultiSelectMode" icon="check-square">
{{ $t('context_menu.select') }}
</MobileActionButton>
<MobileActionButton class="preview-sorting" @click.native="showViewOptions" icon="preview-sorting">
{{$t('preview_sorting.preview_sorting_button')}}
<MobileActionButton @click.native="showViewOptions" icon="preview-sorting">
{{ $t('preview_sorting.preview_sorting_button') }}
</MobileActionButton>
</div>
@@ -68,18 +71,23 @@
import UploadProgress from '@/components/FilesView/UploadProgress'
import {mapGetters} from 'vuex'
import {events} from '@/bus'
import store from "../../store";
export default {
name: 'MobileActions',
name: 'FileActionsMobile',
components: {
MobileActionButtonUpload,
MobileActionButton,
UploadProgress,
},
computed: {
...mapGetters(['FilePreviewType']),
...mapGetters([
'FilePreviewType'
]),
previewIcon() {
return this.FilePreviewType === 'list' ? 'th' : 'th-list'
return this.FilePreviewType === 'list'
? 'th'
: 'th-list'
},
trashLocationMenu() {
return this.$isThisLocation(['trash', 'trash-root']) && this.$checkPermission('master')
@@ -90,14 +98,27 @@
baseLocationVisitorMenu() {
return (this.$isThisLocation(['base', 'shared', 'public']) && this.$checkPermission('visitor')) || (this.$isThisLocation(['latest', 'shared']) && this.$checkPermission('master'))
},
filterLocationTitle() {
return {
'base': 'Files',
'public': 'Files',
'shared': 'Shared',
'latest': 'Latest',
'trash': 'Trash',
'trash-root': 'Trash',
'participant_uploads': 'Participants',
}[this.$store.getters.currentFolder.location]
}
},
data () {
data() {
return {
multiSelectMode: false,
mobileSortingAndPreview: false,
}
},
methods: {
showLocations() {
},
selectAll() {
this.$store.commit('SELECT_ALL_FILES')
},
@@ -115,19 +136,14 @@
events.$emit('mobileSelecting:stop')
},
showViewOptions() {
this.mobileSortingAndPreview = ! this.mobileSortingAndPreview
// Toggle mobile sorting
events.$emit('mobileSortingAndPreview', this.mobileSortingAndPreview)
events.$emit('mobileSortingAndPreviewVignette', this.mobileSortingAndPreview)
events.$emit('mobile-menu:show', 'file-sorting')
},
createFolder() {
events.$emit('popup:open', {name: 'create-folder'})
},
},
mounted () {
events.$on('mobileSelecting:stop', () => this.multiSelectMode = false)
events.$on('mobileSortingAndPreview', state => this.mobileSortingAndPreview = state)
mounted() {
events.$on('mobileSelecting:stop', () => this.multiSelectMode = false)
}
}
</script>
@@ -163,13 +179,6 @@
z-index: 3;
}
.mobile-action-button {
&.is-inactive {
opacity: 0.25;
pointer-events: none;
}
}
.mobile-actions {
white-space: nowrap;
overflow-x: auto;
@@ -20,7 +20,7 @@
<SearchBar class="mobile-search" />
<!--Mobile Actions-->
<MobileActions />
<FileActionsMobile />
<!--Item previews list-->
<div v-if="isList" class="file-list-wrapper">
@@ -92,8 +92,8 @@
</template>
<script>
import FileActionsMobile from '@/components/FilesView/FileActionsMobile'
import MobileToolbar from '@/components/FilesView/MobileToolbar'
import MobileActions from '@/components/FilesView/MobileActions'
import MultiSelected from '@/components/FilesView/MultiSelected'
import FileInfoPanel from '@/components/FilesView/FileInfoPanel'
import FileItemList from '@/components/FilesView/FileItemList'
@@ -107,8 +107,8 @@
export default {
name: 'FilesContainer',
components: {
FileActionsMobile,
MobileToolbar,
MobileActions,
MultiSelected,
FileInfoPanel,
FileItemList,
@@ -1,96 +0,0 @@
<template>
<div
v-if="showFullPreview"
class="file-full-preview-wrapper"
id="fileFullPreview"
ref="filePreview"
tabindex="-1"
@click="closeContextMenu"
@keydown.esc=";(showFullPreview = false), hideContextMenu()"
@keydown.right="next"
@keydown.left="prev"
>
<FilePreviewNavigationPanel />
<MediaFullPreview />
<FilePreviewActions />
</div>
</template>
<script>
import { events } from '@/bus'
import { mapGetters } from 'vuex'
import MediaFullPreview from '@/components/FilesView/MediaFullPreview'
import FilePreviewActions from '@/components/FilesView/FilePreviewActions'
import FilePreviewNavigationPanel from '@/components/FilesView/FilePreviewNavigationPanel'
export default {
name: 'FileFullPreview',
components: {
MediaFullPreview,
FilePreviewNavigationPanel,
FilePreviewActions
},
computed: {
...mapGetters(['fileInfoDetail', 'data'])
},
data() {
return {
showFullPreview: false
}
},
methods: {
closeContextMenu(event) {
if ((event.target.parentElement.id || event.target.id) === 'fast-preview-menu') {
return
} else {
events.$emit('showContextMenuPreview:hide')
}
},
next: function() {
events.$emit('filePreviewAction:next')
},
prev: function() {
events.$emit('filePreviewAction:prev')
},
hideContextMenu() {
events.$emit('showContextMenuPreview:hide')
}
},
updated() {
//Focus file preview for key binding
if (this.showFullPreview) {
this.$refs.filePreview.focus()
}
},
mounted() {
events.$on('fileFullPreview:show', () => {
this.showFullPreview = true
})
events.$on('fileFullPreview:hide', () => {
this.showFullPreview = false
events.$emit('hide:mobile-navigation')
})
}
}
</script>
<style lang="scss" scoped>
@import '@assets/vuefilemanager/_variables';
.file-full-preview-wrapper {
width: 100%;
height: 100%;
position: absolute;
z-index: 7;
background-color: white;
}
@media (prefers-color-scheme: dark) {
.file-full-preview-wrapper {
background-color: $dark_mode_background;
}
}
</style>
@@ -1,7 +1,7 @@
<template>
<div class="file-info-content" v-if="fileInfoDetail.length === 1">
<div class="file-headline" spellcheck="false">
<FilePreview/>
<FilePreviewDetail/>
<!--File info-->
<div class="flex">
@@ -66,8 +66,8 @@
<script>
import {Edit2Icon, LockIcon, UnlockIcon, ImageIcon, VideoIcon, FolderIcon, FileIcon} from 'vue-feather-icons'
import FilePreviewDetail from '@/components/Others/FilePreviewDetail'
import ImageMetaData from '@/components/FilesView/ImageMetaData'
import FilePreview from '@/components/FilesView/FilePreview'
import CopyInput from '@/components/Others/Forms/CopyInput'
import ListInfoItem from '@/components/Others/ListInfoItem'
import ListInfo from '@/components/Others/ListInfo'
@@ -77,10 +77,10 @@
export default {
name: 'FileInfoPanel',
components: {
FilePreviewDetail,
ImageMetaData,
ListInfoItem,
ListInfo,
FilePreview,
FolderIcon,
UnlockIcon,
VideoIcon,
@@ -161,7 +161,7 @@ export default {
this.$store.commit('CLEAR_FILEINFO_DETAIL')
this.$store.commit('GET_FILEINFO_DETAIL', this.item)
events.$emit('mobileMenu:show')
events.$emit('mobile-menu:show', 'file-menu')
},
dragEnter() {
if (this.item.type !== 'folder') return
@@ -155,7 +155,7 @@ export default {
this.$store.commit('CLEAR_FILEINFO_DETAIL')
this.$store.commit('GET_FILEINFO_DETAIL', this.item)
events.$emit('mobileMenu:show')
events.$emit('mobile-menu:show', 'file-menu')
},
dragEnter() {
if (this.item.type !== 'folder') return
@@ -0,0 +1,182 @@
<template>
<MenuMobile name="file-menu">
<ThumbnailItem class="item-thumbnail" :item="fileInfoDetail[0]" info="metadata" />
<!--Trash location-->
<MenuMobileGroup v-if="$isThisLocation(['trash', 'trash-root']) && $checkPermission('master')">
<OptionGroup v-if="fileInfoDetail[0]">
<Option @click.native="restoreItem" :title="$t('context_menu.restore')" icon="restore" />
<Option @click.native="deleteItem" :title="$t('context_menu.delete')" icon="delete" />
</OptionGroup>
<OptionGroup>
<Option v-if="!isFolder" @click.native="downloadItem" :title="$t('context_menu.download')" icon="download" />
<Option v-if="isFolder" @click.native="downloadFolder" :title="$t('context_menu.zip_folder')" icon="zip-folder" />
</OptionGroup>
</MenuMobileGroup>
<!--Shared location-->
<MenuMobileGroup v-if="$isThisLocation(['shared']) && $checkPermission('master')">
<OptionGroup v-if="fileInfoDetail[0] && isFolder">
<Option @click.native="addToFavourites" :title="favouritesTitle" icon="star" />
</OptionGroup>
<OptionGroup v-if="fileInfoDetail[0]">
<Option @click.native="renameItem" :title="$t('context_menu.rename')" icon="rename" />
<Option @click.native="shareItem" :title="fileInfoDetail[0].shared ? $t('context_menu.share_edit') : $t('context_menu.share')" icon="share" />
<Option @click.native="deleteItem" :title="$t('context_menu.delete')" icon="trash" />
</OptionGroup>
<OptionGroup>
<Option v-if="!isFolder" @click.native="downloadItem" :title="$t('context_menu.download')" icon="download" />
<Option v-if="isFolder" @click.native="downloadFolder" :title="$t('context_menu.zip_folder')" icon="zip-folder" />
</OptionGroup>
</MenuMobileGroup>
<!--Base location for user-->
<MenuMobileGroup v-if="$isThisLocation(['base', 'participant_uploads', 'latest']) && $checkPermission('master')">
<OptionGroup v-if="fileInfoDetail[0] && isFolder">
<Option @click.native="addToFavourites" :title="favouritesTitle" icon="star" />
</OptionGroup>
<OptionGroup v-if="fileInfoDetail[0]">
<Option @click.native="renameItem" :title="$t('context_menu.rename')" icon="rename" />
<Option @click.native="moveItem" :title="$t('context_menu.move')" icon="move-item" />
<Option @click.native="shareItem" :title="fileInfoDetail[0].shared ? $t('context_menu.share_edit') : $t('context_menu.share')" icon="share" />
<Option @click.native="deleteItem" :title="$t('context_menu.delete')" icon="trash" />
</OptionGroup>
<OptionGroup>
<Option v-if="!isFolder" @click.native="downloadItem" :title="$t('context_menu.download')" icon="download" />
<Option v-if="isFolder" @click.native="downloadFolder" :title="$t('context_menu.zip_folder')" icon="zip-folder" />
</OptionGroup>
</MenuMobileGroup>
<!--Base location for guest-->
<MenuMobileGroup v-if="$isThisLocation(['base', 'public']) && $checkPermission('editor')">
<OptionGroup>
<Option v-if="fileInfoDetail[0]" @click.native="renameItem" :title="$t('context_menu.rename')" icon="rename" />
<Option v-if="fileInfoDetail[0]" @click.native="moveItem" :title="$t('context_menu.move')" icon="move-item" />
<Option @click.native="deleteItem" :title="$t('context_menu.delete')" icon="trash" />
</OptionGroup>
<OptionGroup>
<Option v-if="!isFolder" @click.native="downloadItem" :title="$t('context_menu.download')" icon="download" />
<Option v-if="isFolder" @click.native="downloadFolder" :title="$t('context_menu.zip_folder')" icon="zip-folder" />
</OptionGroup>
</MenuMobileGroup>
<!--Base location for guest with visit permission-->
<MenuMobileGroup v-if="$isThisLocation(['base', 'public']) && $checkPermission('visitor')">
<OptionGroup>
<Option v-if="!isFolder" @click.native="downloadItem" :title="$t('context_menu.download')" icon="download" />
<Option v-if="isFolder" @click.native="downloadFolder" :title="$t('context_menu.zip_folder')" icon="zip-folder" />
</OptionGroup>
</MenuMobileGroup>
</MenuMobile>
</template>
<script>
import MenuMobileGroup from '@/components/Mobile/MenuMobileGroup'
import MenuMobile from '@/components/Mobile/MenuMobile'
import ThumbnailItem from '@/components/Others/ThumbnailItem'
import OptionGroup from '@/components/FilesView/OptionGroup'
import Option from '@/components/FilesView/Option'
import {mapGetters} from 'vuex'
import {events} from '@/bus'
export default {
name: 'FileMenuMobile',
components: {
MenuMobileGroup,
MenuMobile,
ThumbnailItem,
OptionGroup,
Option,
},
computed: {
...mapGetters([
'fileInfoDetail',
'user',
]),
favourites() {
return this.user.data.relationships.favourites.data.attributes.folders
},
favouritesTitle() {
return this.isInFavourites
? this.$t('context_menu.remove_from_favourites')
: this.$t('context_menu.add_to_favourites')
},
isInFavourites() {
return this.favourites.find(el => el.id === this.fileInfoDetail[0].id)
},
isFile() {
return !this.isImage && !this.isFolder
},
isImage() {
return this.fileInfoDetail[0] && this.fileInfoDetail[0].type === 'image'
},
isFolder() {
return this.fileInfoDetail[0] && this.fileInfoDetail[0].type === 'folder'
}
},
data() {
return {
isVisible: false,
}
},
methods: {
downloadFolder() {
this.$store.dispatch('downloadFolder', this.fileInfoDetail[0])
},
moveItem() {
events.$emit('popup:open', {name: 'move', item: [this.fileInfoDetail[0]]})
},
shareItem() {
if (this.fileInfoDetail[0].shared) {
events.$emit('popup:open', {
name: 'share-edit',
item: this.fileInfoDetail[0]
})
} else {
events.$emit('popup:open', {
name: 'share-create',
item: this.fileInfoDetail[0]
})
}
},
addToFavourites() {
if (this.favourites && !this.favourites.find(el => el.id === this.fileInfoDetail[0].id)) {
this.$store.dispatch('addToFavourites', this.fileInfoDetail[0])
} else {
this.$store.dispatch('removeFromFavourites', this.fileInfoDetail[0])
}
},
downloadItem() {
this.$downloadFile(
this.fileInfoDetail[0].file_url,
this.fileInfoDetail[0].name + '.' + this.fileInfoDetail[0].mimetype
)
},
deleteItem() {
this.$store.dispatch('deleteItem')
},
restoreItem() {
this.$store.dispatch('restoreItem', this.fileInfoDetail[0])
},
renameItem() {
events.$emit('popup:open', {name: 'rename-item', item: this.fileInfoDetail[0]})
},
}
}
</script>
<style scoped lang="scss">
@import "@assets/vuefilemanager/_variables";
@import "@assets/vuefilemanager/_mixins";
.item-thumbnail {
padding: 20px 20px 10px;
margin-bottom: 0;
}
</style>
@@ -1,61 +1,96 @@
<template>
<div v-if="canBePreview" class="preview">
<img v-if="fileInfoDetail[0].type == 'image' && fileInfoDetail[0].thumbnail" :src="fileInfoDetail[0].thumbnail" :alt="fileInfoDetail[0].name" />
<audio v-else-if="fileInfoDetail[0].type == 'audio'" :src="fileInfoDetail[0].file_url" controlsList="nodownload" controls></audio>
<video v-else-if="fileInfoDetail[0].type == 'video'" controlsList="nodownload" disablePictureInPicture playsinline controls>
<source :src="fileInfoDetail[0].file_url" type="video/mp4">
</video>
</div>
<div
v-if="showFullPreview"
class="file-full-preview-wrapper"
id="fileFullPreview"
ref="filePreview"
tabindex="-1"
@click="closeContextMenu"
@keydown.esc=";(showFullPreview = false), hideContextMenu()"
@keydown.right="next"
@keydown.left="prev"
>
<FilePreviewNavigationPanel />
<MediaFullPreview />
<FilePreviewActions />
</div>
</template>
<script>
import { mapGetters } from 'vuex'
import { includes } from 'lodash'
import { events } from '@/bus'
import { mapGetters } from 'vuex'
export default {
name: 'FilePreview',
computed: {
...mapGetters(['fileInfoDetail']),
canBePreview() {
return this.fileInfoDetail[0] && ! includes([
'folder', 'file'
], this.fileInfoDetail[0].type)
}
},
}
import MediaFullPreview from '@/components/FilesView/MediaFullPreview'
import FilePreviewActions from '@/components/FilesView/FilePreviewActions'
import FilePreviewNavigationPanel from '@/components/FilesView/FilePreviewNavigationPanel'
export default {
name: 'FilePreview',
components: {
MediaFullPreview,
FilePreviewNavigationPanel,
FilePreviewActions
},
computed: {
...mapGetters(['fileInfoDetail', 'data'])
},
data() {
return {
showFullPreview: false
}
},
methods: {
closeContextMenu(event) {
if ((event.target.parentElement.id || event.target.id) === 'fast-preview-menu') {
return
} else {
events.$emit('showContextMenuPreview:hide')
}
},
next: function() {
events.$emit('filePreviewAction:next')
},
prev: function() {
events.$emit('filePreviewAction:prev')
},
hideContextMenu() {
events.$emit('showContextMenuPreview:hide')
}
},
updated() {
//Focus file preview for key binding
if (this.showFullPreview) {
this.$refs.filePreview.focus()
}
},
mounted() {
events.$on('fileFullPreview:show', () => {
this.showFullPreview = true
})
events.$on('fileFullPreview:hide', () => {
this.showFullPreview = false
events.$emit('mobile-navigation:hide')
})
}
}
</script>
<style scoped lang="scss">
@import '@assets/vuefilemanager/_variables';
@import '@assets/vuefilemanager/_mixins';
<style lang="scss" scoped>
@import '@assets/vuefilemanager/_variables';
.preview {
width: 100%;
display: block;
margin-bottom: 7px;
.file-full-preview-wrapper {
width: 100%;
height: 100%;
position: absolute;
z-index: 7;
background-color: white;
}
img {
border-radius: 4px;
overflow: hidden;
width: 100%;
object-fit: cover;
}
audio {
width: 100%;
&::-webkit-media-controls-panel {
background-color: $light_background;
}
&::-webkit-media-controls-play-button {
color: $theme;
}
}
video {
width: 100%;
height: auto;
border-radius: 3px;
}
}
@media (prefers-color-scheme: dark) {
.file-full-preview-wrapper {
background-color: $dark_mode_background;
}
}
</style>
@@ -93,7 +93,7 @@ export default {
},
menuOpen() {
if (this.$isMobile()) {
events.$emit('mobileMenu:show', 'showFromMediaPreview')
events.$emit('mobile-menu:show', 'file-menu')
} else {
events.$emit('showContextMenuPreview:show', this.fileInfoDetail[0])
}
@@ -0,0 +1,22 @@
<template>
<MenuMobile name="file-sorting">
<MenuMobileGroup>
<FileSortingOptions />
</MenuMobileGroup>
</MenuMobile>
</template>
<script>
import FileSortingOptions from '@/components/FilesView/FileSortingOptions'
import MenuMobileGroup from '@/components/Mobile/MenuMobileGroup'
import MenuMobile from '@/components/Mobile/MenuMobile'
export default {
name: 'FilterSortingMobile',
components: {
FileSortingOptions,
MenuMobileGroup,
MenuMobile,
},
}
</script>
@@ -1,10 +1,10 @@
<template>
<div class="menu-options" id="menu-list">
<OptionGroup class="menu-option-group">
<div>
<OptionGroup>
<Option v-if="isList" @click.native="changePreview('grid')" :title="$t('preview_sorting.grid_view')" icon="grid" />
<Option v-if="isGrid" @click.native="changePreview('list')" :title="$t('preview_sorting.list_view')" icon="list" />
</OptionGroup>
<OptionGroup class="menu-option-group">
<OptionGroup>
<Option @click.native.stop="sort('created_at')" :title="$t('preview_sorting.sort_date')" icon="calendar" />
<Option @click.native.stop="sort('name')" :title="$t('preview_sorting.sort_alphabet')" icon="alphabet" />
</OptionGroup>
@@ -19,25 +19,20 @@
import OptionGroup from '@/components/FilesView/OptionGroup'
import Option from '@/components/FilesView/Option'
import { CalendarIcon, ListIcon, GridIcon, ArrowUpIcon, CheckIcon } from 'vue-feather-icons'
import AlphabetIcon from '@/components/FilesView/Icons/AlphabetIcon'
import { ArrowUpIcon } from 'vue-feather-icons'
import { mapGetters } from 'vuex'
import { events } from '@/bus'
export default {
name: 'SortingAndPreviewMenu',
name: 'FileSortingOptions',
components: {
OptionGroup,
Option,
CalendarIcon,
AlphabetIcon,
ArrowUpIcon,
CheckIcon,
ListIcon,
GridIcon
Option,
},
computed: {
...mapGetters(['FilePreviewType']),
...mapGetters([
'FilePreviewType'
]),
isGrid() {
return this.FilePreviewType === 'grid'
},
@@ -55,7 +50,6 @@ export default {
},
methods: {
sort(field) {
this.filter.field = field
// Set sorting direction
@@ -74,16 +68,10 @@ export default {
this.$getDataByLocation()
},
changePreview(previewType) {
this.$store.dispatch('changePreviewType', previewType)
if (this.$isMobile())
events.$emit('mobileSortingAndPreview', false)
events.$emit('mobileSortingAndPreviewVignette', this.mobileSortingAndPreview)
}
},
mounted() {
let sorting = JSON.parse(localStorage.getItem('sorting'))
// Set default sorting if in not setup in LocalStorage
@@ -92,89 +80,3 @@ export default {
}
}
</script>
<style scoped lang="scss">
@import "@assets/vuefilemanager/_variables";
@import "@assets/vuefilemanager/_mixins";
.show-icon {
margin-left: auto;
max-height: 19px;
.arrow-down {
@include transform(rotate(180deg));
}
}
.menu-option {
display: flex;
.icon {
margin-right: 20px;
line-height: 0;
}
.text-label {
@include font-size(16);
}
}
.sorting-preview {
min-width: 250px;
position: absolute;
z-index: 99;
box-shadow: $shadow;
background: white;
border-radius: 8px;
overflow: hidden;
right: 66px;
top: 63px;
&.showed {
display: block;
}
}
.menu-options {
list-style: none;
width: 100%;
margin: 0;
padding: 0;
.menu-option-group {
padding: 5px 0;
border-bottom: 1px solid $light_mode_border;
&:first-child {
padding-top: 0;
}
&:last-child {
padding-bottom: 0;
border-bottom: none;
}
}
.menu-option {
white-space: nowrap;
font-weight: 700;
@include font-size(14);
padding: 15px 20px;
cursor: pointer;
width: 100%;
color: $text;
}
}
@media (prefers-color-scheme: dark) {
.menu-options {
.menu-option-group {
border-color: $dark_mode_border_color;
}
.menu-option {
color: $dark_mode_text_primary;
}
}
}
</style>
@@ -1,6 +1,7 @@
<template>
<button class="mobile-action-button">
<div class="flex">
<filter-icon v-if="icon === 'filter'" size="15" class="icon dark-text-theme" />
<credit-card-icon v-if="icon === 'credit-card'" size="15" class="icon dark-text-theme" />
<folder-plus-icon v-if="icon === 'folder-plus'" size="15" class="icon dark-text-theme" />
<list-icon v-if="icon === 'th-list'" size="15" class="icon dark-text-theme" />
@@ -21,7 +22,7 @@
</template>
<script>
import { DollarSignIcon, CheckIcon, XSquareIcon, CheckSquareIcon, FolderPlusIcon, ListIcon, GridIcon, TrashIcon, UserPlusIcon, PlusIcon, CreditCardIcon } from 'vue-feather-icons'
import { FilterIcon, DollarSignIcon, CheckIcon, XSquareIcon, CheckSquareIcon, FolderPlusIcon, ListIcon, GridIcon, TrashIcon, UserPlusIcon, PlusIcon, CreditCardIcon } from 'vue-feather-icons'
import SortingAndPreviewIcon from '@/components/FilesView/Icons/SortingAndPreviewIcon'
export default {
@@ -37,6 +38,7 @@
FolderPlusIcon,
UserPlusIcon,
XSquareIcon,
FilterIcon,
CheckIcon,
TrashIcon,
PlusIcon,
@@ -1,560 +0,0 @@
<template>
<div class="options-wrapper">
<transition name="context-menu">
<div v-if="isVisible" ref="contextmenu" class="options" @click="closeAndResetContextMenu">
<div class="menu-wrapper">
<!--Item Thumbnail-->
<ThumbnailItem class="item-thumbnail" :item="fileInfoDetail[0]" info="metadata"/>
<!--Mobile for trash location-->
<div v-if="$isThisLocation(['trash', 'trash-root']) && $checkPermission('master')" class="menu-options">
<ul class="menu-option-group">
<li class="menu-option" @click="$store.dispatch('restoreItem', fileInfoDetail[0])" v-if="fileInfoDetail[0]">
<div class="icon">
<life-buoy-icon size="17"></life-buoy-icon>
</div>
<div class="text-label">
{{ $t('context_menu.restore') }}
</div>
</li>
<li class="menu-option delete" @click="deleteItem" v-if="fileInfoDetail[0]">
<div class="icon">
<trash-2-icon size="17"></trash-2-icon>
</div>
<div class="text-label">
{{ $t('context_menu.delete') }}
</div>
</li>
</ul>
<ul class="menu-option-group" >
<li class="menu-option" @click="downloadItem" v-if="!isFolder">
<div class="icon">
<download-cloud-icon size="17"></download-cloud-icon>
</div>
<div class="text-label">
{{ $t('context_menu.download') }}
</div>
</li>
<li class="menu-option" @click="downloadFolder" v-if="isFolder">
<div class="icon">
<paperclip-icon size="17"></paperclip-icon>
</div>
<div class="text-label">
{{ $t('context_menu.zip_folder') }}
</div>
</li>
</ul>
</div>
<!--Mobile for Base location-->
<div v-if="$isThisLocation(['shared']) && $checkPermission('master')" class="menu-options">
<ul class="menu-option-group">
<li class="menu-option" @click="addToFavourites" v-if="fileInfoDetail[0] && isFolder">
<div class="icon">
<star-icon size="17"></star-icon>
</div>
<div class="text-label">
{{
isInFavourites
? $t('context_menu.remove_from_favourites')
: $t('context_menu.add_to_favourites')
}}
</div>
</li>
</ul>
<ul class="menu-option-group">
<li class="menu-option" @click="renameItem" v-if="fileInfoDetail[0]">
<div class="icon">
<edit-2-icon size="17"></edit-2-icon>
</div>
<div class="text-label">
{{ $t('context_menu.rename') }}
</div>
</li>
<li class="menu-option" @click="shareItem" v-if="fileInfoDetail[0]">
<div class="icon">
<link-icon size="17"></link-icon>
</div>
<div class="text-label">
{{
fileInfoDetail[0].shared
? $t('context_menu.share_edit')
: $t('context_menu.share')
}}
</div>
</li>
<li class="menu-option delete" @click="deleteItem" v-if="fileInfoDetail[0]">
<div class="icon">
<trash-2-icon size="17"></trash-2-icon>
</div>
<div class="text-label">
{{ $t('context_menu.delete') }}
</div>
</li>
</ul>
<ul class="menu-option-group">
<li class="menu-option" @click="downloadItem" v-if="!isFolder">
<div class="icon">
<download-cloud-icon size="17"></download-cloud-icon>
</div>
<div class="text-label">
{{ $t('context_menu.download') }}
</div>
</li>
<li class="menu-option" @click="downloadFolder" v-if="isFolder">
<div class="icon">
<paperclip-icon size="17"></paperclip-icon>
</div>
<div class="text-label">
{{ $t('context_menu.zip_folder') }}
</div>
</li>
</ul>
</div>
<!--Mobile for Base location-->
<div v-if="$isThisLocation(['base', 'participant_uploads', 'latest']) && $checkPermission('master')" class="menu-options">
<ul class="menu-option-group" v-if="fileInfoDetail[0] && isFolder">
<li class="menu-option" @click="addToFavourites">
<div class="icon">
<star-icon size="17"></star-icon>
</div>
<div class="text-label">
{{
isInFavourites
? $t('context_menu.remove_from_favourites')
: $t('context_menu.add_to_favourites')
}}
</div>
</li>
</ul>
<ul class="menu-option-group">
<li class="menu-option" @click="renameItem" v-if="fileInfoDetail[0]">
<div class="icon">
<edit-2-icon size="17"></edit-2-icon>
</div>
<div class="text-label">
{{ $t('context_menu.rename') }}
</div>
</li>
<li class="menu-option" @click="moveItem" v-if="fileInfoDetail[0]">
<div class="icon">
<corner-down-right-icon size="17"></corner-down-right-icon>
</div>
<div class="text-label">
{{ $t('context_menu.move') }}
</div>
</li>
<li class="menu-option" @click="shareItem" v-if="fileInfoDetail[0]">
<div class="icon">
<link-icon size="17"></link-icon>
</div>
<div class="text-label">
{{
fileInfoDetail[0].shared
? $t('context_menu.share_edit')
: $t('context_menu.share')
}}
</div>
</li>
<li class="menu-option delete" @click="deleteItem" v-if="fileInfoDetail[0]">
<div class="icon">
<trash-2-icon size="17"></trash-2-icon>
</div>
<div class="text-label">
{{ $t('context_menu.delete') }}
</div>
</li>
</ul>
<ul class="menu-option-group">
<li class="menu-option" @click="downloadItem" v-if="!isFolder">
<div class="icon">
<download-cloud-icon size="17"></download-cloud-icon>
</div>
<div class="text-label">
{{ $t('context_menu.download') }}
</div>
</li>
<li class="menu-option" @click="downloadFolder" v-if="isFolder">
<div class="icon">
<paperclip-icon size="17"></paperclip-icon>
</div>
<div class="text-label">
{{ $t('context_menu.zip_folder') }}
</div>
</li>
</ul>
</div>
<!--Mobile for Base location with EDITOR permission-->
<div v-if="$isThisLocation(['base', 'public']) && $checkPermission('editor')" class="menu-options">
<ul class="menu-option-group">
<li class="menu-option" @click="renameItem" v-if="fileInfoDetail[0]">
<div class="icon">
<edit-2-icon size="17"></edit-2-icon>
</div>
<div class="text-label">
{{ $t('context_menu.rename') }}
</div>
</li>
<li class="menu-option" @click="moveItem" v-if="fileInfoDetail[0]">
<div class="icon">
<corner-down-right-icon size="17"></corner-down-right-icon>
</div>
<div class="text-label">
{{ $t('context_menu.move') }}
</div>
</li>
<li class="menu-option" @click="deleteItem">
<div class="icon">
<trash-2-icon size="17"></trash-2-icon>
</div>
<div class="text-label">
{{ $t('context_menu.delete') }}
</div>
</li>
</ul>
<ul class="menu-option-group">
<li class="menu-option" @click="downloadItem" v-if="!isFolder">
<div class="icon">
<download-cloud-icon size="17"></download-cloud-icon>
</div>
<div class="text-label">
{{ $t('context_menu.download') }}
</div>
</li>
<li class="menu-option" @click="downloadFolder" v-if="isFolder">
<div class="icon">
<paperclip-icon size="17"></paperclip-icon>
</div>
<div class="text-label">
{{ $t('context_menu.zip_folder') }}
</div>
</li>
</ul>
</div>
<!--Mobile for Base location with VISITOR permission-->
<div v-if="$isThisLocation(['base', 'public']) && $checkPermission('visitor')" class="menu-options">
<ul class="menu-option-group">
<li class="menu-option" @click="downloadItem" v-if="!isFolder">
<div class="icon">
<download-cloud-icon size="17"></download-cloud-icon>
</div>
<div class="text-label">
{{ $t('context_menu.download') }}
</div>
</li>
<li class="menu-option" @click="downloadFolder" v-if="isFolder">
<div class="icon">
<paperclip-icon size="17"></paperclip-icon>
</div>
<div class="text-label">
{{ $t('context_menu.zip_folder') }}
</div>
</li>
</ul>
</div>
</div>
</div>
</transition>
<transition name="fade">
<div v-show="isVisible" class="vignette" @click="closeAndResetContextMenu"></div>
</transition>
</div>
</template>
<script>
import ThumbnailItem from '@/components/Others/ThumbnailItem'
import {
CornerDownRightIcon,
DownloadCloudIcon,
FolderPlusIcon,
PaperclipIcon,
LifeBuoyIcon,
Trash2Icon,
Edit2Icon,
TrashIcon,
StarIcon,
LinkIcon,
EyeIcon
} from 'vue-feather-icons'
import { events } from '@/bus'
import { mapGetters } from 'vuex'
export default {
name: 'MobileMenu',
components: {
CornerDownRightIcon,
DownloadCloudIcon,
FolderPlusIcon,
PaperclipIcon,
ThumbnailItem,
LifeBuoyIcon,
Trash2Icon,
Edit2Icon,
TrashIcon,
LinkIcon,
StarIcon,
EyeIcon
},
computed: {
...mapGetters(['fileInfoDetail', 'user']),
favourites() {
return this.user.data.relationships.favourites.data.attributes.folders
},
isInFavourites() {
return this.favourites.find(
(el) => el.id == this.fileInfoDetail[0].id
)
},
isFile() {
return (
this.fileInfoDetail[0] &&
this.fileInfoDetail[0].type !== 'folder' &&
this.fileInfoDetail[0] &&
this.fileInfoDetail[0].type !== 'image'
)
},
isImage() {
return this.fileInfoDetail[0] && this.fileInfoDetail[0].type === 'image'
},
isFolder() {
return this.fileInfoDetail[0] && this.fileInfoDetail[0].type === 'folder'
}
},
data() {
return {
isVisible: false,
showFromMediaPreview: false
}
},
methods: {
downloadFolder(){
this.$store.dispatch( 'downloadFolder' , this.fileInfoDetail[0] )
},
moveItem() {
events.$emit('popup:open', { name: 'move', item: [this.fileInfoDetail[0]] })
},
shareItem() {
if (this.fileInfoDetail[0].shared) {
// Open share item popup
events.$emit('popup:open', {
name: 'share-edit',
item: this.fileInfoDetail[0]
})
} else {
// Open share item popup
events.$emit('popup:open', {
name: 'share-create',
item: this.fileInfoDetail[0]
})
}
},
addToFavourites() {
if (
this.favourites &&
!this.favourites.find(
(el) => el.id == this.fileInfoDetail[0].id
)
) {
this.$store.dispatch('addToFavourites', this.fileInfoDetail[0])
} else {
this.$store.dispatch('removeFromFavourites', this.fileInfoDetail[0])
}
},
downloadItem() {
this.$downloadFile(
this.fileInfoDetail[0].file_url,
this.fileInfoDetail[0].name + '.' + this.fileInfoDetail[0].mimetype
)
},
deleteItem() {
this.$store.dispatch('deleteItem')
},
renameItem() {
events.$emit('popup:open', { name: 'rename-item', item: this.fileInfoDetail[0] })
},
closeAndResetContextMenu() {
//If emit to show menu coming from MediaFullPreview dont reset data
this.isVisible = false
this.showFromMediaPreview = false
events.$emit('hide:mobile-navigation')
}
},
created() {
events.$on('mobileMenu:show', showFromMedia => {
// If emit come from MediaFullPreview
if (showFromMedia) {
this.isVisible = true
this.showFromMediaPreview = true
} else {
this.isVisible = !this.isVisible
}
})
// Hide mobile menu
events.$on('mobileMenu:hide', () => {
this.isVisible = false
})
}
}
</script>
<style scoped lang="scss">
@import "@assets/vuefilemanager/_variables";
@import "@assets/vuefilemanager/_mixins";
.mobile-selected-menu {
display: flex;
margin-left: 15px;
margin-right: 15px;
.close-icon {
margin-left: auto !important;
}
}
.menu-option {
display: flex;
align-items: center;
.icon {
margin-right: 20px;
line-height: 0;
}
.text-label {
@include font-size(16);
}
}
.vignette {
background: rgba(0, 0, 0, 0.35);
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
z-index: 9;
cursor: pointer;
opacity: 1;
}
.options {
position: absolute;
bottom: 0;
left: 0;
right: 0;
z-index: 99;
overflow: hidden;
background: white;
border-top-left-radius: 12px;
border-top-right-radius: 12px;
&.showed {
display: block;
}
.item-thumbnail {
padding: 20px 20px 10px;
margin-bottom: 0px;
}
.menu-options {
margin-top: 10px;
list-style: none;
width: 100%;
.menu-option-group {
padding: 5px 0;
border-bottom: 1px solid $light_mode_border;
&:first-child {
padding-top: 0;
}
&:last-child {
padding-bottom: 0;
border-bottom: none;
}
}
.menu-option {
font-weight: 700;
letter-spacing: 0.15px;
@include font-size(14);
cursor: pointer;
width: 100%;
padding: 17px 20px;
text-align: center;
&:last-child {
border: none;
}
}
}
}
@media (prefers-color-scheme: dark) {
.vignette {
background: $dark_mode_vignette;
}
.options {
background: $dark_mode_foreground;
.menu-options {
background: $dark_mode_foreground;
.menu-option-group {
border-color: $dark_mode_border_color;
}
.menu-option {
color: $dark_mode_text_primary;
}
}
}
}
// Transition
.context-menu-enter-active,
.fade-enter-active {
transition: all 200ms;
}
.context-menu-leave-active,
.fade-leave-active {
transition: all 200ms;
}
.fade-enter,
.fade-leave-to {
opacity: 0;
}
.context-menu-enter,
.context-menu-leave-to {
opacity: 0;
transform: translateY(100%);
}
.context-menu-leave-active {
position: absolute;
}
</style>
@@ -1,76 +0,0 @@
<template>
<transition v-if="isVisible" name="preview-menu" >
<SortingAndPreviewMenu class="options"/>
</transition>
</template>
<script>
import SortingAndPreviewMenu from '@/components/FilesView/SortingAndPreviewMenu'
import { events } from '@/bus'
export default {
name: 'MobileSortingAndPreview',
components: {SortingAndPreviewMenu},
data () {
return {
isVisible: false
}
},
mounted () {
events.$on('mobileSortingAndPreview', (state) => {
this.isVisible = state
})
}
}
</script>
<style scoped lang="scss">
@import "@assets/vuefilemanager/_variables";
@import "@assets/vuefilemanager/_mixins";
.options {
position: absolute;
bottom: 0;
left: 0;
right: 0;
z-index: 99;
overflow: hidden;
background: white;
border-top-left-radius: 12px;
border-top-right-radius: 12px;
}
@media (prefers-color-scheme: dark) {
.options {
background: $dark_mode_foreground;
}
}
// Transition
.preview-menu-enter-active,
.fade-enter-active {
transition: all 200ms;
}
.preview-menu-leave-active,
.fade-leave-active {
transition: all 200ms;
}
.fade-enter,
.fade-leave-to {
opacity: 0;
}
.preview-menu-enter,
.preview-menu-leave-to {
opacity: 0;
transform: translateY(100%);
}
.preview-menu-leave-active {
position: absolute;
}
</style>
@@ -51,7 +51,7 @@
},
methods: {
showMobileNavigation() {
events.$emit('show:mobile-navigation')
events.$emit('mobile-navigation:show')
events.$emit('mobileSelecting:stop')
},
goBack() {
@@ -1,27 +1,27 @@
<template>
<transition name="context-menu">
<div class="multiselect-actions" v-if="mobileMultiSelect">
<ToolbarButton class="action-btn" v-if="!$isThisLocation(['trash', 'trash-root' , 'shared', 'latest']) && $checkPermission('master') || $checkPermission('editor')" source="move" :action="$t('actions.move')" :class="{'is-inactive' : fileInfoDetail.length < 1}" @click.native="moveItem"/>
<ToolbarButton class="action-btn" v-if="!$isThisLocation(['trash', 'trash-root' , 'shared', 'latest']) && $checkPermission('master') || $checkPermission('editor')" source="move" :action="$t('actions.move')" :class="{'is-inactive' : fileInfoDetail.length < 1}" @click.native="moveItem" />
<ToolbarButton class="action-btn" v-if="!$isThisLocation(['shared']) && $checkPermission('master') || $checkPermission('editor')" source="trash" :class="{'is-inactive' : fileInfoDetail.length < 1}" :action="$t('actions.delete')" @click.native="deleteItem"/>
<ToolbarButton class="action-btn" v-if="!$isThisLocation(['shared']) && $checkPermission('master') || $checkPermission('editor')" source="trash" :class="{'is-inactive' : fileInfoDetail.length < 1}" :action="$t('actions.delete')" @click.native="deleteItem" />
<ToolbarButton class="action-btn" v-if="!$isThisLocation(['shared'])" source="download" :class="{'is-inactive': canDownloadItems}" :action="$t('actions.delete')" @click.native="downloadItem"/>
<ToolbarButton class="action-btn" v-if="!$isThisLocation(['shared'])" source="download" :class="{'is-inactive': canDownloadItems}" :action="$t('actions.delete')" @click.native="downloadItem" />
<ToolbarButton class="action-btn" source="shared-off" @click.native="shareCancel" v-if="$isThisLocation(['shared'])"/>
<ToolbarButton class="action-btn" source="shared-off" @click.native="shareCancel" v-if="$isThisLocation(['shared'])" />
<ToolbarButton class="action-btn close-icon" source="close" :action="$t('actions.close')" @click.native="closeSelecting"/>
<ToolbarButton class="action-btn close-icon" source="close" :action="$t('actions.close')" @click.native="closeSelecting" />
</div>
</transition>
</template>
<script>
import ToolbarButton from '@/components/FilesView/ToolbarButton'
import { events } from '@/bus'
import { mapGetters } from 'vuex'
import {events} from '@/bus'
import {mapGetters} from 'vuex'
export default {
name: 'MobileMultiSelectMenu',
components: { ToolbarButton },
name: 'MultiSelectToolbarMobile',
components: {ToolbarButton},
computed: {
...mapGetters(['fileInfoDetail']),
canDownloadItems() {
@@ -34,7 +34,7 @@ export default {
}
},
methods: {
shareCancel() {
shareCancel() {
this.$store.dispatch('shareCancel')
this.closeSelecting()
},
@@ -51,7 +51,7 @@ export default {
},
moveItem() {
// Open move item popup
events.$emit('popup:open', { name: 'move', item: [this.fileInfoDetail[0]] })
events.$emit('popup:open', {name: 'move', item: [this.fileInfoDetail[0]]})
},
deleteItem() {
//Delete items
@@ -120,37 +120,37 @@ export default {
}
}
@media (prefers-color-scheme: dark) {
@media (prefers-color-scheme: dark) {
.multiselect-actions {
background: $dark_mode_foreground;
}
.multiselect-actions {
background: $dark_mode_foreground;
}
}
// Transition
.context-menu-enter-active,
.fade-enter-active {
transition: all 200ms;
}
// Transition
.context-menu-enter-active,
.fade-enter-active {
transition: all 200ms;
}
.context-menu-leave-active,
.fade-leave-active {
transition: all 200ms;
}
.context-menu-leave-active,
.fade-leave-active {
transition: all 200ms;
}
.fade-enter,
.fade-leave-to {
opacity: 0;
}
.fade-enter,
.fade-leave-to {
opacity: 0;
}
.context-menu-enter,
.context-menu-leave-to {
opacity: 0;
transform: translateY(100%);
}
.context-menu-enter,
.context-menu-leave-to {
opacity: 0;
transform: translateY(100%);
}
.context-menu-leave-active {
position: absolute;
}
.context-menu-leave-active {
position: absolute;
}
</style>
@@ -17,6 +17,7 @@
<smile-icon v-if="icon === 'no-options'" size="17" class="group-hover-text-theme"/>
<paperclip-icon v-if="icon === 'zip-folder'" size="17" class="group-hover-text-theme"/>
<alphabet-icon v-if="icon === 'alphabet'" size="17" class="group-hover-text-theme"/>
<star-icon v-if="icon === 'star'" size="17" class="group-hover-text-theme"/>
</div>
<div class="text-label group-hover-text-theme">
{{ title }}