v1.5-alpha.1

This commit is contained in:
carodej
2020-05-15 17:31:25 +02:00
parent cfecf542ca
commit 41656235fc
97 changed files with 4108 additions and 2118 deletions
+2 -1
View File
@@ -88,7 +88,8 @@
</script>
<style scoped lang="scss">
@import "@assets/app.scss";
@import '@assets/vue-file-manager/_variables';
@import '@assets/vue-file-manager/_mixins';
.popup {
position: absolute;
@@ -15,10 +15,11 @@
</script>
<style scoped lang="scss">
@import "@assets/app.scss";
@import '@assets/vue-file-manager/_variables';
@import '@assets/vue-file-manager/_mixins';
.button-base {
@include font-size(16);
@include font-size(15);
font-weight: 700;
cursor: pointer;
transition: 0.15s all ease;
@@ -31,10 +31,11 @@
</script>
<style scoped lang="scss">
@import "@assets/app.scss";
@import '@assets/vue-file-manager/_variables';
@import '@assets/vue-file-manager/_mixins';
.button-base {
@include font-size(16);
@include font-size(15);
font-weight: 700;
cursor: pointer;
transition: 0.15s all ease;
+334 -101
View File
@@ -7,105 +7,270 @@
ref="contextmenu"
>
<!--ContextMenu for trash location-->
<ul v-if="$isThisLocation(['trash', 'trash-root']) && $checkPermission('master')" class="menu-options" ref="list">
<li class="menu-option" @click="deleteItem" v-if="item">
{{ $t('context_menu.delete') }}
</li>
<li class="menu-option" @click="$store.dispatch('restoreItem', item)" v-if="item">
{{ $t('context_menu.restore') }}
</li>
<li class="menu-option" @click="$store.dispatch('emptyTrash')">
{{ $t('context_menu.empty_trash') }}
</li>
<li class="menu-option" @click="ItemDetail" v-if="item">
{{ $t('context_menu.detail') }}
</li>
<li class="menu-option" @click="downloadItem" v-if="! isFolder && item">
{{ $t('context_menu.download') }}
</li>
</ul>
<div v-if="$isThisLocation(['trash', 'trash-root']) && $checkPermission('master')" id="menu-list" class="menu-options">
<ul class="menu-option-group">
<li class="menu-option" @click="$store.dispatch('restoreItem', item)" v-if="item">
<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" @click="$store.dispatch('emptyTrash')">
<div class="icon">
<trash-icon size="17"></trash-icon>
</div>
<div class="text-label">
{{ $t('context_menu.empty_trash') }}
</div>
</li>
<li class="menu-option" @click="deleteItem" v-if="item">
<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="ItemDetail" v-if="item">
<div class="icon">
<eye-icon size="17"></eye-icon>
</div>
<div class="text-label">
{{ $t('context_menu.detail') }}
</div>
</li>
<li class="menu-option" @click="downloadItem" v-if="! isFolder && item">
<div class="icon">
<download-cloud-icon size="17"></download-cloud-icon>
</div>
<div class="text-label">
{{ $t('context_menu.download') }}
</div>
</li>
</ul>
</div>
<!--ContextMenu for Base location with MASTER permission-->
<ul v-if="$isThisLocation(['shared']) && $checkPermission('master')" class="menu-options" ref="list">
<li class="menu-option" @click="addToFavourites" v-if="item && isFolder">
{{ isInFavourites ? $t('context_menu.remove_from_favourites') : $t('context_menu.add_to_favourites') }}
</li>
<li class="menu-option" @click="deleteItem" v-if="item">
{{ $t('context_menu.delete') }}
</li>
<li class="menu-option" @click="shareItem" v-if="item">
{{ item.shared ? $t('context_menu.share_edit') : $t('context_menu.share') }}
</li>
<li class="menu-option" @click="ItemDetail" v-if="item">
{{ $t('context_menu.detail') }}
</li>
<li class="menu-option" @click="downloadItem" v-if="! isFolder && item">
{{ $t('context_menu.download') }}
</li>
</ul>
<div v-if="$isThisLocation(['shared']) && $checkPermission('master')" id="menu-list" class="menu-options">
<ul class="menu-option-group">
<li class="menu-option" @click="addToFavourites" v-if="item && 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="deleteItem" v-if="item">
<div class="icon">
<trash-2-icon size="17"></trash-2-icon>
</div>
<div class="text-label">
{{ $t('context_menu.delete') }}
</div>
</li>
<li class="menu-option" @click="shareItem" v-if="item">
<div class="icon">
<link-icon size="17"></link-icon>
</div>
<div class="text-label">
{{ item.shared ? $t('context_menu.share_edit') : $t('context_menu.share') }}
</div>
</li>
</ul>
<ul class="menu-option-group">
<li class="menu-option" @click="ItemDetail" v-if="item">
<div class="icon">
<eye-icon size="17"></eye-icon>
</div>
<div class="text-label">
{{ $t('context_menu.detail') }}
</div>
</li>
<li class="menu-option" @click="downloadItem" v-if="! isFolder && item">
<div class="icon">
<download-cloud-icon size="17"></download-cloud-icon>
</div>
<div class="text-label">
{{ $t('context_menu.download') }}
</div>
</li>
</ul>
</div>
<!--ContextMenu for Base location with MASTER permission-->
<ul v-if="$isThisLocation(['base']) && $checkPermission('master')" class="menu-options" ref="list">
<li class="menu-option" @click="addToFavourites" v-if="item && isFolder">
{{ isInFavourites ? $t('context_menu.remove_from_favourites') : $t('context_menu.add_to_favourites') }}
</li>
<li class="menu-option" @click="createFolder">
{{ $t('context_menu.create_folder') }}
</li>
<li class="menu-option" @click="deleteItem" v-if="item">
{{ $t('context_menu.delete') }}
</li>
<li class="menu-option" @click="moveItem" v-if="item">
{{ $t('context_menu.move') }}
</li>
<li class="menu-option" @click="shareItem" v-if="item">
{{ item.shared ? $t('context_menu.share_edit') : $t('context_menu.share') }}
</li>
<li class="menu-option" @click="ItemDetail" v-if="item">
{{ $t('context_menu.detail') }}
</li>
<li class="menu-option" @click="downloadItem" v-if="! isFolder && item">
{{ $t('context_menu.download') }}
</li>
</ul>
<div v-if="$isThisLocation(['base', 'participant_uploads', 'latest']) && $checkPermission('master')" id="menu-list" class="menu-options">
<ul class="menu-option-group" v-if="! $isThisLocation(['participant_uploads', 'latest'])">
<li class="menu-option" @click="addToFavourites" v-if="item && 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>
<li class="menu-option" @click="createFolder">
<div class="icon">
<folder-plus-icon size="17"></folder-plus-icon>
</div>
<div class="text-label">
{{ $t('context_menu.create_folder') }}
</div>
</li>
</ul>
<ul class="menu-option-group">
<li class="menu-option" @click="moveItem" v-if="item">
<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="item">
<div class="icon">
<link-icon size="17"></link-icon>
</div>
<div class="text-label">
{{ item.shared ? $t('context_menu.share_edit') : $t('context_menu.share') }}
</div>
</li>
<li class="menu-option" @click="deleteItem" v-if="item">
<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="ItemDetail" v-if="item">
<div class="icon">
<eye-icon size="17"></eye-icon>
</div>
<div class="text-label">
{{ $t('context_menu.detail') }}
</div>
</li>
<li class="menu-option" @click="downloadItem" v-if="! isFolder && item">
<div class="icon">
<download-cloud-icon size="17"></download-cloud-icon>
</div>
<div class="text-label">
{{ $t('context_menu.download') }}
</div>
</li>
</ul>
</div>
<!--ContextMenu for Base location with EDITOR permission-->
<ul v-if="$isThisLocation(['base', 'public']) && $checkPermission('editor')" class="menu-options" ref="list">
<li class="menu-option" @click="createFolder">
{{ $t('context_menu.create_folder') }}
</li>
<li class="menu-option" @click="deleteItem" v-if="item">
{{ $t('context_menu.delete') }}
</li>
<li class="menu-option" @click="moveItem" v-if="item">
{{ $t('context_menu.move') }}
</li>
<li class="menu-option" @click="ItemDetail" v-if="item">
{{ $t('context_menu.detail') }}
</li>
<li class="menu-option" @click="downloadItem" v-if="! isFolder && item">
{{ $t('context_menu.download') }}
</li>
</ul>
<div v-if="$isThisLocation(['base', 'public']) && $checkPermission('editor')" id="menu-list" class="menu-options">
<ul class="menu-option-group">
<li class="menu-option" @click="createFolder">
<div class="icon">
<folder-plus-icon size="17"></folder-plus-icon>
</div>
<div class="text-label">
{{ $t('context_menu.create_folder') }}
</div>
</li>
</ul>
<ul class="menu-option-group" v-if="item && isFolder">
<li class="menu-option" @click="moveItem" v-if="item">
<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" v-if="item">
<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" v-if="item && isFolder">
<li class="menu-option" @click="ItemDetail" v-if="item">
<div class="icon">
<eye-icon size="17"></eye-icon>
</div>
<div class="text-label">
{{ $t('context_menu.detail') }}
</div>
</li>
<li class="menu-option" @click="downloadItem" v-if="! isFolder && item">
<div class="icon">
<download-cloud-icon size="17"></download-cloud-icon>
</div>
<div class="text-label">
{{ $t('context_menu.download') }}
</div>
</li>
</ul>
</div>
<!--ContextMenu for Base location with VISITOR permission-->
<ul v-if="$isThisLocation(['base', 'public']) && $checkPermission('visitor')" class="menu-options" ref="list">
<div v-if="$isThisLocation(['base', 'public']) && $checkPermission('visitor')" id="menu-list" class="menu-options">
<li class="menu-option" @click="ItemDetail" v-if="item">
{{ $t('context_menu.detail') }}
<div class="icon">
<eye-icon size="17"></eye-icon>
</div>
<div class="text-label">
{{ $t('context_menu.detail') }}
</div>
</li>
<li class="menu-option" @click="downloadItem" v-if="! isFolder && item">
{{ $t('context_menu.download') }}
<div class="icon">
<download-cloud-icon size="17"></download-cloud-icon>
</div>
<div class="text-label">
{{ $t('context_menu.download') }}
</div>
</li>
</ul>
</div>
</div>
</template>
<script>
import {
CornerDownRightIcon,
DownloadCloudIcon,
FolderPlusIcon,
LifeBuoyIcon,
Trash2Icon,
TrashIcon,
StarIcon,
LinkIcon,
EyeIcon,
} from 'vue-feather-icons'
import {mapGetters} from 'vuex'
import {events} from '@/bus'
export default {
name: 'ContextMenu',
components: {
CornerDownRightIcon,
DownloadCloudIcon,
FolderPlusIcon,
LifeBuoyIcon,
Trash2Icon,
TrashIcon,
LinkIcon,
StarIcon,
EyeIcon,
},
computed: {
...mapGetters(['app']),
isFolder() {
@@ -145,7 +310,7 @@
},
addToFavourites() {
// Check if folder is in favourites and then add/remove from favourites
if (this.app.favourites && ! this.app.favourites.find(el => el.unique_id == this.item.unique_id)) {
if (this.app.favourites && !this.app.favourites.find(el => el.unique_id == this.item.unique_id)) {
this.$store.dispatch('addToFavourites', this.item)
} else {
this.$store.dispatch('removeFromFavourites', this.item)
@@ -159,6 +324,7 @@
)
},
ItemDetail() {
// Dispatch load file info detail
this.$store.commit('GET_FILEINFO_DETAIL', this.item)
@@ -180,8 +346,20 @@
// Reset item container
this.item = undefined
},
showContextMenu(event, item) {
let VerticalOffsetArea = item && this.$refs.list.children ? this.$refs.list.children.length * 50 : 50
showFolderActionsMenu() {
let container = document.getElementById('folder-actions')
this.positionX = container.offsetLeft + 16
this.positionY = container.offsetTop + 30
// Show context menu
this.isVisible = true
},
showContextMenu(event) {
let parent = document.getElementById('menu-list')
let nodesSameClass = parent.getElementsByClassName("menu-option")
let VerticalOffsetArea = nodesSameClass.length * 50
let HorizontalOffsetArea = 190
let container = document.getElementById('files-view')
@@ -220,15 +398,42 @@
})
events.$on('contextMenu:hide', () => (this.closeAndResetContextMenu()))
events.$on('folder:actions', folder => {
// Store item
this.item = folder
if (this.isVisible)
this.isVisible = false
else
this.showFolderActionsMenu()
})
}
}
</script>
<style scoped lang="scss">
@import "@assets/app.scss";
@import '@assets/vue-file-manager/_variables';
@import '@assets/vue-file-manager/_mixins';
.menu-option {
display: flex;
align-items: center;
.icon {
margin-right: 20px;
line-height: 0;
}
.text-label {
@include font-size(16);
}
}
.contextmenu {
min-width: 190px;
min-width: 250px;
position: absolute;
z-index: 99;
box-shadow: $shadow;
@@ -239,26 +444,47 @@
&.showed {
display: block;
}
}
.menu-options {
list-style: none;
.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%;
margin: 0;
padding: 0;
color: $text;
.menu-option {
white-space: nowrap;
font-weight: 700;
@include font-size(15);
padding: 15px 30px;
cursor: pointer;
width: 100%;
color: $text;
&:hover {
background: $light_background;
&:hover {
background: $light_background;
.text-label {
color: $theme;
}
path, line, polyline, rect, circle, polygon {
stroke: $theme;
}
}
}
}
@@ -268,11 +494,18 @@
.contextmenu {
background: $dark_mode_foreground;
.menu-options .menu-option {
color: $dark_mode_text_primary;
.menu-options {
&:hover {
background: $dark_mode_background;
.menu-option-group {
border-color: $dark_mode_border_color;
}
.menu-option {
color: $dark_mode_text_primary;
&:hover {
background: rgba($theme, 0.1);
}
}
}
}
@@ -1,41 +1,57 @@
<template>
<div id="desktop-toolbar" v-if="! $isMinimalScale()">
<div id="desktop-toolbar">
<div class="toolbar-wrapper">
<!-- Go back-->
<div class="toolbar-go-back" v-if="homeDirectory">
<div @click="goBack" class="go-back-button">
<FontAwesomeIcon
v-if="browseHistory.length > 0"
class="icon-back"
icon="chevron-left"
></FontAwesomeIcon>
<chevron-left-icon size="17" :class="{'is-active': browseHistory.length > 1}" class="icon-back"></chevron-left-icon>
<span class="back-directory-title">
{{ directoryName }}
</span>
<span @click.stop="folderActions" v-if="browseHistory.length > 1 && $isThisLocation(['base', 'public'])" class="folder-options" id="folder-actions">
<more-horizontal-icon size="14" class="icon-more"></more-horizontal-icon>
</span>
</div>
</div>
<!-- Tools-->
<div class="toolbar-tools">
<!--Search bar-->
<div class="toolbar-button-wrapper">
<SearchBar/>
</div>
<!--Files controlls-->
<div class="toolbar-button-wrapper" v-if="$checkPermission(['master', 'editor'])">
<div class="toolbar-button-wrapper"
v-if="$checkPermission(['master', 'editor'])">
<ToolbarButtonUpload
source="upload"
:class="{'is-inactive': canUploadInView}"
:action="$t('actions.upload')"
/>
<ToolbarButton
source="trash-alt"
:action="$t('actions.delete')"
@click.native="deleteItems"
source="move"
:class="{'is-inactive': canMoveInView}"
action="Move"
@click.native="moveItem"
/>
<ToolbarButton
v-if="! $isThisLocation(['public'])"
source="share"
:class="{'is-inactive': canShareInView}"
action="Share"
@click.native="shareItem"
/>
<ToolbarButton
source="trash"
:class="{'is-inactive': canDeleteInView}"
:action="$t('actions.delete')"
@click.native="deleteItem"
/>
<ToolbarButton
:class="{'is-inactive': canCreateFolderInView}"
@click.native="createFolder"
source="folder-plus"
:action="$t('actions.create_folder')"
@@ -63,89 +79,108 @@
<script>
import ToolbarButtonUpload from '@/components/FilesView/ToolbarButtonUpload'
import { ChevronLeftIcon, MoreHorizontalIcon } from 'vue-feather-icons'
import UploadProgress from '@/components/FilesView/UploadProgress'
import ToolbarButton from '@/components/FilesView/ToolbarButton'
import SearchBar from '@/components/FilesView/SearchBar'
import {mapGetters} from 'vuex'
import {events} from '@/bus'
import {last} from 'lodash'
export default {
name: 'ToolBar',
components: {
ToolbarButtonUpload,
MoreHorizontalIcon,
ChevronLeftIcon,
UploadProgress,
ToolbarButton,
SearchBar
},
computed: {
...mapGetters([
'FilePreviewType',
'fileInfoVisible',
'fileInfoDetail',
'currentFolder',
'browseHistory',
'homeDirectory',
'FilePreviewType',
]),
directoryName() {
return this.currentFolder ? this.currentFolder.name : this.homeDirectory.name
},
previousFolder() {
const length = this.browseHistory.length - 2
return this.browseHistory[length] ? this.browseHistory[length] : this.homeDirectory
},
preview() {
return this.FilePreviewType === 'list' ? 'th' : 'th-list'
},
},
data() {
return {
isSidebarMenu: false,
canCreateFolderInView() {
return ! this.$isThisLocation(['base', 'public'])
},
canDeleteInView() {
return ! this.$isThisLocation(['trash', 'trash-root', 'base', 'participant_uploads', 'latest', 'shared', 'public'])
},
canUploadInView() {
return ! this.$isThisLocation(['base', 'public'])
},
canMoveInView() {
return ! this.$isThisLocation(['base', 'participant_uploads', 'latest', 'shared', 'public'])
},
canShareInView() {
return ! this.$isThisLocation(['base', 'participant_uploads', 'latest', 'shared', 'public'])
}
},
methods: {
showSidebarMenu() {
this.isSidebarMenu = ! this.isSidebarMenu
events.$emit('show:sidebar')
},
goBack() {
// Get previous folder
let previousFolder = last(this.browseHistory)
if (this.previousFolder.location === 'trash-root') {
if (! previousFolder)
return
if (previousFolder.location === 'trash-root') {
this.$store.dispatch('getTrash')
this.$store.commit('FLUSH_BROWSER_HISTORY')
} else if (previousFolder.location === 'shared') {
this.$store.dispatch('getShared')
} else {
if ( this.$isThisLocation('public') ) {
this.$store.dispatch('browseShared', [this.previousFolder, true])
this.$store.dispatch('browseShared', [{folder: previousFolder, back: true, init: false}])
} else {
this.$store.dispatch('getFolder', [this.previousFolder, true])
this.$store.dispatch('getFolder', [{folder: previousFolder, back: true, init: false}])
}
}
},
deleteItems() {
folderActions() {
events.$emit('folder:actions', this.currentFolder)
},
deleteItem() {
events.$emit('items:delete')
},
createFolder() {
if (! this.$isThisLocation(['trash', 'trash-root']))
this.$createFolder()
this.$createFolder()
},
moveItem() {
events.$emit('popup:open', {name: 'move', item: this.fileInfoDetail})
},
shareItem() {
if (this.fileInfoDetail.shared) {
events.$emit('popup:open', {name: 'share-edit', item: this.fileInfoDetail})
} else {
events.$emit('popup:open', {name: 'share-create', item: this.fileInfoDetail})
}
}
},
created() {
// Listen for hide sidebar
events.$on('show:content', () => {
if (this.isSidebarMenu) this.isSidebarMenu = false
})
}
}
</script>
<style scoped lang="scss">
@import "@assets/app.scss";
@import '@assets/vue-file-manager/_variables';
@import '@assets/vue-file-manager/_mixins';
.toolbar-wrapper {
padding-top: 15px;
padding-bottom: 15px;
padding-top: 10px;
padding-bottom: 10px;
display: flex;
position: relative;
z-index: 2;
@@ -171,13 +206,48 @@
.icon-back {
vertical-align: middle;
cursor: pointer;
margin-right: 12px;
margin-right: 6px;
opacity: 0.15;
pointer-events: none;
@include transition(150ms);
&.is-active {
opacity: 1;
pointer-events: initial;
}
}
.toolbar-go-back {
cursor: pointer;
.folder-options {
vertical-align: middle;
margin-left: 6px;
padding: 1px 4px;
line-height: 0;
border-radius: 3px;
@include transition(150ms);
svg circle {
@include transition(150ms);
}
&:hover {
background: $light_background;
svg circle {
stroke: $theme;
}
}
.icon-more {
vertical-align: middle;
}
}
.back-directory-title {
@include font-size(15);
line-height: 1;
font-weight: 700;
overflow: hidden;
@@ -201,7 +271,7 @@
text-align: right;
.toolbar-button-wrapper {
margin-left: 75px;
margin-left: 28px;
display: inline-block;
vertical-align: middle;
@@ -210,8 +280,13 @@
}
}
button {
margin-left: 20px;
.button {
margin-left: 5px;
&.is-inactive {
opacity: 0.25;
pointer-events: none;
}
&:first-child {
margin-left: 0;
@@ -219,6 +294,33 @@
}
}
@media only screen and (max-width: 1024px) {
.toolbar-go-back .back-directory-title {
max-width: 120px;
}
.toolbar-tools {
.button {
margin-left: 0;
height: 40px;
width: 40px;
}
.toolbar-button-wrapper {
margin-left: 25px;
}
}
}
@media only screen and (max-width: 960px) {
#desktop-toolbar {
display: none;
}
}
@media (prefers-color-scheme: dark) {
.toolbar .directory-name {
color: $dark_mode_text_primary;
@@ -229,6 +331,13 @@
.back-directory-title {
color: $dark_mode_text_primary;
}
.folder-options {
&:hover {
background: $dark_mode_foreground;
}
}
}
}
</style>
@@ -1,21 +1,27 @@
<template>
<div class="empty-message">
<div class="message">
<FontAwesomeIcon class="icon" :icon="icon"/>
<eye-off-icon v-if="icon === 'eye-off'" size="36" class="icon"></eye-off-icon>
<p>{{ message }}</p>
</div>
</div>
</template>
<script>
import { EyeOffIcon } from 'vue-feather-icons'
export default {
name: 'EmptyMessage',
props: ['icon', 'message']
props: ['icon', 'message'],
components: {
EyeOffIcon
}
}
</script>
<style scoped lang="scss">
@import "@assets/app.scss";
@import '@assets/vue-file-manager/_variables';
@import '@assets/vue-file-manager/_mixins';
.empty-message {
text-align: center;
@@ -35,11 +41,8 @@
}
.icon {
@include font-size(36);
color: $text;
path {
fill: $text;
path, line, polyline, rect, circle {
stroke: $text;
}
}
}
@@ -47,8 +50,9 @@
@media (prefers-color-scheme: dark) {
.empty-message .message .icon {
path {
fill: $dark_mode_text_secondary;
path, line, polyline, rect, circle {
stroke: $dark_mode_text_secondary;
}
}
}
@@ -18,7 +18,6 @@
<p v-if="$checkPermission(['master', 'editor'])" class="description">{{ $t('empty_page.description') }}</p>
<ButtonUpload
v-if="$checkPermission(['master', 'editor'])"
@input.native="$uploadFiles"
button-style="theme"
>
{{ $t('empty_page.call_to_action') }}
@@ -55,7 +54,8 @@
</script>
<style scoped lang="scss">
@import "@assets/app.scss";
@import '@assets/vue-file-manager/_variables';
@import '@assets/vue-file-manager/_mixins';
.empty-page {
position: absolute;
@@ -15,7 +15,7 @@
<MobileToolbar />
<!--Searchbar-->
<SearchBar v-if="$isMinimalScale()" class="mobile-search"/>
<SearchBar class="mobile-search" />
<!--Mobile Actions-->
<MobileActions />
@@ -77,7 +77,7 @@
<FileInfoPanel v-if="fileInfoDetail"/>
<!--If file info panel empty show message-->
<EmptyMessage v-if="!fileInfoDetail" :message="$t('messages.nothing_to_preview')" icon="eye-slash"/>
<EmptyMessage v-if="!fileInfoDetail" :message="$t('messages.nothing_to_preview')" icon="eye-off"/>
</div>
</div>
</template>
@@ -209,7 +209,8 @@
</script>
<style scoped lang="scss">
@import "@assets/app.scss";
@import '@assets/vue-file-manager/_variables';
@import '@assets/vue-file-manager/_mixins';
.button-upload {
display: block;
@@ -218,6 +219,7 @@
}
.mobile-search {
display: none;
margin-bottom: 10px;
margin-top: 10px;
}
@@ -276,11 +278,70 @@
transform: translateX(-20px);
}
.file-leave-active {
position: absolute;
@media only screen and (min-width: 960px) {
.file-content {
position: absolute;
top: 72px;
left: 15px;
right: 15px;
bottom: 0;
@include transition;
&.is-offset {
margin-top: 50px;
}
}
}
@media only screen and (max-width: 660px) {
@media only screen and (max-width: 960px) {
.file-info-container {
display: none;
}
.mobile-search {
display: block;
}
}
@media only screen and (max-width: 690px) {
.file-list {
&.grid {
grid-template-columns: repeat(auto-fill, 120px);
}
}
.files-container {
padding-left: 15px;
padding-right: 15px;
top: 0;
left: 0;
right: 0;
bottom: 0;
position: absolute;
overflow-y: auto;
}
.file-content {
position: absolute;
top: 0;
left: 0px;
right: 0px;
bottom: 0;
@include transition;
&.is-offset {
margin-top: 50px;
}
}
.mobile-search {
margin-bottom: 0;
}
.file-info-container {
display: none;
}
@@ -7,12 +7,15 @@
<div class="flex">
<div class="icon">
<div class="icon-preview">
<FontAwesomeIcon :icon="filePreviewIcon"></FontAwesomeIcon>
<image-icon v-if="fileType === 'image'" size="21"></image-icon>
<video-icon v-if="fileType === 'video'" size="21"></video-icon>
<folder-icon v-if="fileType === 'folder'" size="21"></folder-icon>
<file-icon v-if="fileType === 'file'" size="21"></file-icon>
</div>
</div>
<div class="file-info">
<span ref="name" class="name">{{ fileInfoDetail.name }}</span>
<span class="mimetype" v-if="fileInfoDetail.mimetype">{{ fileInfoDetail.mimetype }}</span>
<span class="mimetype" v-if="fileInfoDetail.mimetype">.{{ fileInfoDetail.mimetype }}</span>
</div>
</div>
</div>
@@ -42,8 +45,8 @@
<li v-if="$checkPermission(['master'])" class="list-info-item">
<b>{{ $t('file_detail.where') }}</b>
<div class="action-button" @click="moveItem">
<FontAwesomeIcon class="icon" icon="pencil-alt" />
<span>{{ fileInfoDetail.parent ? fileInfoDetail.parent.name : $t('locations.home') }}</span>
<edit-2-icon size="10" class="edit-icon"></edit-2-icon>
</div>
</li>
@@ -51,11 +54,13 @@
<li v-if="$checkPermission('master') && fileInfoDetail.shared" class="list-info-item">
<b>{{ $t('file_detail.shared') }}</b>
<div class="action-button" @click="shareItemOptions">
<FontAwesomeIcon class="icon" :icon="sharedIcon" />
<span>{{ sharedInfo }}</span>
<edit-2-icon size="10" class="edit-icon"></edit-2-icon>
</div>
<div class="sharelink">
<FontAwesomeIcon class="lock-icon" :icon="lockIcon" @click="shareItemOptions" />
<lock-icon v-if="isLocked" @click="shareItemOptions" class="lock-icon" size="17"></lock-icon>
<unlock-icon v-if="! isLocked" @click="shareItemOptions" class="lock-icon" size="17"></unlock-icon>
<CopyInput class="copy-sharelink" size="small" :value="fileInfoDetail.shared.link" />
</div>
</li>
@@ -64,6 +69,7 @@
</template>
<script>
import { Edit2Icon, LockIcon, UnlockIcon, ImageIcon, VideoIcon, FolderIcon, FileIcon } from 'vue-feather-icons'
import FilePreview from '@/components/FilesView/FilePreview'
import CopyInput from '@/components/Others/Forms/CopyInput'
import {mapGetters} from 'vuex'
@@ -73,12 +79,20 @@
name: 'FileInfoPanel',
components: {
FilePreview,
FolderIcon,
UnlockIcon,
VideoIcon,
CopyInput,
ImageIcon,
FileIcon,
Edit2Icon,
LockIcon,
},
computed: {
...mapGetters(['fileInfoDetail', 'permissionOptions']),
filePreviewIcon() {
switch (this.fileInfoDetail.type) {
fileType() {
return this.fileInfoDetail.type
/* switch () {
case 'folder':
return 'folder'
break;
@@ -94,7 +108,7 @@
case 'file':
return 'file-audio'
break;
}
}*/
},
sharedInfo() {
@@ -117,8 +131,8 @@
return 'download'
}
},
lockIcon() {
return this.fileInfoDetail.shared.protected ? 'lock' : 'lock-open'
isLocked() {
return this.fileInfoDetail.shared.protected
}
},
methods: {
@@ -135,15 +149,14 @@
</script>
<style scoped lang="scss">
@import "@assets/app.scss";
@import '@assets/vue-file-manager/_variables';
@import '@assets/vue-file-manager/_mixins';
.file-info-content {
padding-bottom: 20px;
}
.file-headline {
background: $light_background;
padding: 12px;
margin-bottom: 20px;
border-radius: 8px;
@@ -153,37 +166,19 @@
}
.icon-preview {
height: 42px;
width: 42px;
border-radius: 8px;
display: inline-flex;
align-items: center;
justify-content: center;
padding: 0;
background: white;
text-align: center;
cursor: pointer;
white-space: nowrap;
outline: none;
border: none;
/deep/ svg {
@include font-size(22);
path {
fill: $theme;
}
}
&:hover {
.icon path {
fill: $theme;
}
}
}
.file-info {
padding-left: 12px;
padding-left: 10px;
width: 100%;
word-break: break-all;
@@ -196,7 +191,7 @@
}
.mimetype {
@include font-size(14);
@include font-size(12);
font-weight: 600;
color: $theme;
display: block;
@@ -205,11 +200,10 @@
}
.list-info {
padding-left: 12px;
.list-info-item {
display: block;
padding-top: 15px;
padding-top: 20px;
&:first-child {
padding-top: 0;
@@ -218,14 +212,9 @@
.action-button {
cursor: pointer;
.icon {
@include font-size(10);
.edit-icon {
display: inline-block;
margin-right: 2px;
path {
fill: $theme;
}
margin-left: 3px;
}
}
@@ -252,22 +241,10 @@
margin-top: 10px;
.lock-icon {
@include font-size(10);
display: inline-block;
width: 10px;
width: 15px;
margin-right: 9px;
cursor: pointer;
path {
fill: $text;
}
&:hover {
path {
fill: $theme;
}
}
}
.copy-sharelink {
@@ -278,11 +255,6 @@
@media (prefers-color-scheme: dark) {
.file-headline {
background: $dark_mode_foreground;
.icon-preview {
background: $dark_mode_background;
}
.file-info {
@@ -313,14 +285,10 @@
.lock-icon {
path {
fill: $dark_mode_text_primary;
}
&:hover {
path {
fill: $theme;
path, rect {
stroke: $theme;
}
}
}
@@ -52,12 +52,12 @@
<!--Shared Icon-->
<div v-if="$checkPermission('master') && data.shared" class="item-shared">
<FontAwesomeIcon class="shared-icon" icon="share"/>
<link-icon size="12" class="shared-icon"></link-icon>
</div>
<!--Participant owner Icon-->
<div v-if="$checkPermission('master') && data.user_scope !== 'master'" class="item-shared">
<FontAwesomeIcon class="shared-icon" icon="user-edit"/>
<user-plus-icon size="12" class="shared-icon"></user-plus-icon>
</div>
<!--Filesize-->
@@ -79,6 +79,7 @@
</template>
<script>
import { LinkIcon, UserPlusIcon } from 'vue-feather-icons'
import {debounce} from 'lodash'
import {mapGetters} from 'vuex'
import {events} from '@/bus'
@@ -86,6 +87,10 @@
export default {
name: 'FileItemGrid',
props: ['data'],
components: {
UserPlusIcon,
LinkIcon,
},
computed: {
...mapGetters([
'FilePreviewType', 'sharedDetail'
@@ -155,9 +160,9 @@
// Go to folder
if (this.$isThisLocation('public')) {
this.$store.dispatch('browseShared', [this.data, false])
this.$store.dispatch('browseShared', [{folder: this.data, back: false, init: false}])
} else {
this.$store.dispatch('getFolder', [this.data, false])
this.$store.dispatch('getFolder', [{folder: this.data, back: false, init: false}])
}
}
@@ -187,11 +192,11 @@
}
if (this.isFolder) {
// Go to folder
if (this.$isThisLocation('public')) {
this.$store.dispatch('browseShared', [this.data, false])
this.$store.dispatch('browseShared', [{folder: this.data, back: false, init: false}])
} else {
this.$store.dispatch('getFolder', [this.data, false])
this.$store.dispatch('getFolder', [{folder: this.data, back: false, init: false}])
}
}
},
@@ -224,7 +229,8 @@
</script>
<style scoped lang="scss">
@import "@assets/app.scss";
@import '@assets/vue-file-manager/_variables';
@import '@assets/vue-file-manager/_mixins';
.show-actions {
cursor: pointer;
@@ -240,6 +246,7 @@
}
.file-wrapper {
user-select: none;
position: relative;
text-align: center;
display: inline-block;
@@ -254,9 +261,9 @@
.item-size,
.item-length {
@include font-size(12);
@include font-size(11);
font-weight: 400;
color: $text-muted;
color: rgba($text, 0.7);
display: inline-block;
}
@@ -275,10 +282,10 @@
}
.shared-icon {
@include font-size(9);
vertical-align: middle;
path {
fill: $theme;
path, circle, line {
stroke: $theme;
}
}
}
@@ -404,6 +411,55 @@
}
}
@media only screen and (max-width: 960px) {
.file-wrapper {
.icon-item {
margin-bottom: 15px;
}
}
}
@media only screen and (max-width: 690px) {
.file-wrapper {
.file-item {
width: 120px;
}
.icon-item {
margin-bottom: 10px;
height: 90px;
.file-icon {
@include font-size(75);
}
.file-icon-text {
@include font-size(12);
}
.folder-icon {
@include font-size(75);
margin-top: 0;
margin-bottom: 0;
}
.image {
width: 90px;
height: 90px;
}
}
.item-name .name {
@include font-size(13);
line-height: .9;
max-height: 30px;
}
}
}
@media (prefers-color-scheme: dark) {
.file-wrapper {
@@ -51,12 +51,12 @@
<!--Shared Icon-->
<div v-if="$checkPermission('master') && data.shared" class="item-shared">
<FontAwesomeIcon class="shared-icon" icon="share"/>
<link-icon size="12" class="shared-icon"></link-icon>
</div>
<!--Participant owner Icon-->
<div v-if="$checkPermission('master') && data.user_scope !== 'master'" class="item-shared">
<FontAwesomeIcon class="shared-icon" icon="user-edit"/>
<user-plus-icon size="12" class="shared-icon"></user-plus-icon>
</div>
<!--Filesize and timestamp-->
@@ -80,6 +80,7 @@
</template>
<script>
import { LinkIcon, UserPlusIcon } from 'vue-feather-icons'
import {debounce} from 'lodash'
import {mapGetters} from 'vuex'
import {events} from '@/bus'
@@ -87,6 +88,10 @@
export default {
name: 'FileItemList',
props: ['data'],
components: {
UserPlusIcon,
LinkIcon,
},
computed: {
...mapGetters(['FilePreviewType']),
isFolder() {
@@ -164,9 +169,9 @@
// Go to folder
if (this.$isThisLocation('public')) {
this.$store.dispatch('browseShared', [this.data, false])
this.$store.dispatch('browseShared', [{folder: this.data, back: false, init: false}])
} else {
this.$store.dispatch('getFolder', [this.data, false])
this.$store.dispatch('getFolder', [{folder: this.data, back: false, init: false}])
}
}
@@ -194,9 +199,9 @@
if (this.isFolder) {
if (this.$isThisLocation('public')) {
this.$store.dispatch('browseShared', [this.data, false])
this.$store.dispatch('browseShared', [{folder: this.data, back: false, init: false}])
} else {
this.$store.dispatch('getFolder', [this.data, false])
this.$store.dispatch('getFolder', [{folder: this.data, back: false, init: false}])
}
}
},
@@ -229,9 +234,11 @@
</script>
<style scoped lang="scss">
@import "@assets/app.scss";
@import '@assets/vue-file-manager/_variables';
@import '@assets/vue-file-manager/_mixins';
.file-wrapper {
user-select: none;
position: relative;
&:hover {
@@ -278,19 +285,19 @@
}
.shared-icon {
@include font-size(9);
vertical-align: middle;
path {
fill: $theme;
path, circle, line {
stroke: $theme;
}
}
}
.item-size,
.item-length {
@include font-size(12);
@include font-size(11);
font-weight: 400;
color: $text-muted;
color: rgba($text, 0.7);
}
.name {
@@ -412,6 +419,7 @@
}
@media (prefers-color-scheme: dark) {
.file-wrapper {
.icon-item .file-icon {
@@ -437,8 +445,16 @@
}
}
.item-name .name {
color: $dark_mode_text_primary;
.item-name {
.name {
color: $dark_mode_text_primary;
}
.item-size,
.item-length {
color: $dark_mode_text_secondary;
}
}
}
}
@@ -26,7 +26,8 @@
</script>
<style scoped lang="scss">
@import "@assets/app.scss";
@import '@assets/vue-file-manager/_variables';
@import '@assets/vue-file-manager/_mixins';
.preview {
width: 100%;
@@ -1,24 +1,37 @@
<template>
<button class="mobile-action-button">
<FontAwesomeIcon class="icon" :icon="icon"></FontAwesomeIcon>
<span class="label">
<slot></slot>
</span>
<div class="flex">
<folder-plus-icon v-if="icon === 'folder-plus'" size="15" class="icon"></folder-plus-icon>
<list-icon v-if="icon === 'th-list'" size="15" class="icon"></list-icon>
<trash-icon v-if="icon === 'trash'" size="15" class="icon"></trash-icon>
<grid-icon v-if="icon === 'th'" size="15" class="icon"></grid-icon>
<span class="label">
<slot></slot>
</span>
</div>
</button>
</template>
<script>
import { FolderPlusIcon, ListIcon, GridIcon, TrashIcon } from 'vue-feather-icons'
export default {
name: 'MobileActionButton',
props: [
'icon'
],
components: {
FolderPlusIcon,
TrashIcon,
ListIcon,
GridIcon,
}
}
</script>
<style scoped lang="scss">
@import "@assets/app.scss";
@import '@assets/vue-file-manager/_variables';
@import '@assets/vue-file-manager/_mixins';
.mobile-action-button {
background: $light_background;
@@ -28,6 +41,11 @@
cursor: pointer;
border: none;
.flex {
display: flex;
align-items: center;
}
.icon {
margin-right: 10px;
@include font-size(14);
@@ -44,8 +62,8 @@
.mobile-action-button {
background: $dark_mode_foreground;
.icon path {
fill: $theme;
path, line, polyline, rect, circle {
stroke: $theme;
}
.label {
@@ -1,31 +1,29 @@
<template>
<button class="mobile-action-button">
<FontAwesomeIcon class="icon" :icon="icon"></FontAwesomeIcon>
<label label="file" class="label button file-input button-base">
<slot></slot>
<input
accept="*"
v-show="false"
@change="emmitFiles"
id="file"
type="file"
name="files[]"
multiple
/>
</label>
<div class="flex">
<upload-cloud-icon class="icon" size="15"></upload-cloud-icon>
<label label="file" class="label button file-input button-base">
<slot></slot>
<input
@change="emmitFiles"
v-show="false"
id="file"
type="file"
name="files[]"
multiple
/>
</label>
</div>
</button>
</template>
<script>
import { UploadCloudIcon } from 'vue-feather-icons'
export default {
name: 'MobileActionButtonUpload',
props: [
'icon'
],
data() {
return {
files: undefined
}
components: {
UploadCloudIcon,
},
methods: {
emmitFiles(e) {
@@ -36,8 +34,8 @@
</script>
<style scoped lang="scss">
@import "@assets/app.scss";
@import '@assets/vue-file-manager/_variables';
@import '@assets/vue-file-manager/_mixins';
.mobile-action-button {
background: $light_background;
@@ -47,12 +45,19 @@
cursor: pointer;
border: none;
.flex {
display: flex;
align-items: center;
}
.icon {
margin-right: 8px;
vertical-align: middle;
margin-right: 10px;
@include font-size(14);
}
.label {
vertical-align: middle;
@include font-size(14);
font-weight: 700;
color: $text;
@@ -63,8 +68,8 @@
.mobile-action-button {
background: $dark_mode_foreground;
.icon path {
fill: $theme;
path, line, polyline, rect, circle {
stroke: $theme;
}
.label {
@@ -1,22 +1,22 @@
<template>
<div id="mobile-actions-wrapper" v-if="$isMinimalScale()">
<div id="mobile-actions-wrapper">
<!--Actions for trash location with MASTER permission--->
<div v-if="$isThisLocation(['trash', 'trash-root']) && $checkPermission('master')" class="mobile-actions">
<MobileActionButton @click.native="switchPreview" :icon="previewIcon">
{{ previewText }}
</MobileActionButton>
<MobileActionButton @click.native="$store.dispatch('emptyTrash')" icon="trash-alt">
<MobileActionButton @click.native="$store.dispatch('emptyTrash')" icon="trash">
{{ $t('context_menu.empty_trash') }}
</MobileActionButton>
</div>
<!--ContextMenu for Base location with MASTER permission-->
<div v-if="$isThisLocation(['base', 'shared', 'public']) && $checkPermission(['master', 'editor'])" class="mobile-actions">
<div v-if="$isThisLocation(['base', 'public']) && $checkPermission(['master', 'editor'])" class="mobile-actions">
<MobileActionButton @click.native="createFolder" icon="folder-plus">
{{ $t('context_menu.add_folder') }}
</MobileActionButton>
<MobileActionButtonUpload @input.native="$uploadFiles" icon="upload">
<MobileActionButtonUpload>
{{ $t('context_menu.upload') }}
</MobileActionButtonUpload>
<MobileActionButton @click.native="switchPreview" :icon="previewIcon">
@@ -25,7 +25,7 @@
</div>
<!--ContextMenu for Base location with VISITOR permission-->
<div v-if="$isThisLocation(['base', 'shared', 'public']) && $checkPermission('visitor')" class="mobile-actions">
<div v-if="($isThisLocation(['base', 'shared', 'public']) && $checkPermission('visitor')) || ($isThisLocation(['latest', 'shared']) && $checkPermission('master'))" class="mobile-actions">
<MobileActionButton @click.native="switchPreview" :icon="previewIcon">
{{ previewText }}
</MobileActionButton>
@@ -81,10 +81,11 @@
</script>
<style scoped lang="scss">
@import "@assets/app.scss";
@import '@assets/vue-file-manager/_variables';
@import '@assets/vue-file-manager/_mixins';
#mobile-actions-wrapper {
display: none;
background: white;
position: sticky;
top: 35px;
@@ -98,6 +99,13 @@
overflow-x: auto;
}
@media only screen and (max-width: 960px) {
#mobile-actions-wrapper {
display: block;
}
}
@media (prefers-color-scheme: dark) {
#mobile-actions-wrapper {
background: $dark_mode_background;
+262 -74
View File
@@ -9,79 +9,205 @@
>
<div class="menu-wrapper">
<!--Item Thumbnail-->
<ThumbnailItem class="item-thumbnail" :item="fileInfoDetail" info="metadata"/>
<!--Mobile for trash location-->
<ul v-if="$isThisLocation(['trash', 'trash-root']) && $checkPermission('master')" class="menu-options">
<li class="menu-option" @click="$store.dispatch('restoreItem', fileInfoDetail)" v-if="fileInfoDetail">
{{ $t('context_menu.restore') }}
</li>
<li class="menu-option" @click="downloadItem" v-if="! isFolder">
{{ $t('context_menu.download') }}
</li>
<li class="menu-option delete" @click="deleteItem" v-if="fileInfoDetail">
{{ $t('context_menu.delete') }}
</li>
</ul>
<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)" v-if="fileInfoDetail">
<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">
<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" v-if="! isFolder">
<li class="menu-option" @click="downloadItem">
<div class="icon">
<download-cloud-icon size="17"></download-cloud-icon>
</div>
<div class="text-label">
{{ $t('context_menu.download') }}
</div>
</li>
</ul>
</div>
<!--Mobile for Base location-->
<ul v-if="$isThisLocation(['shared']) && $checkPermission('master')" class="menu-options">
<li class="menu-option" @click="addToFavourites" v-if="fileInfoDetail && isFolder">
{{ isInFavourites ? $t('context_menu.remove_from_favourites') : $t('context_menu.add_to_favourites') }}
</li>
<li class="menu-option" @click="renameItem" v-if="fileInfoDetail">
{{ $t('context_menu.rename') }}
</li>
<li class="menu-option" @click="shareItem" v-if="fileInfoDetail">
{{ fileInfoDetail.shared ? $t('context_menu.share_edit') : $t('context_menu.share') }}
</li>
<li class="menu-option" @click="downloadItem" v-if="! isFolder">
{{ $t('context_menu.download') }}
</li>
<li class="menu-option delete" @click="deleteItem" v-if="fileInfoDetail">
{{ $t('context_menu.delete') }}
</li>
</ul>
<div v-if="$isThisLocation(['shared']) && $checkPermission('master')" class="menu-options">
<ul class="menu-option-group">
<li class="menu-option" @click="addToFavourites" v-if="fileInfoDetail && 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">
<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">
<div class="icon">
<link-icon size="17"></link-icon>
</div>
<div class="text-label">
{{ fileInfoDetail.shared ? $t('context_menu.share_edit') : $t('context_menu.share') }}
</div>
</li>
<li class="menu-option delete" @click="deleteItem" v-if="fileInfoDetail">
<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>
</ul>
</div>
<!--Mobile for Base location-->
<ul v-if="$isThisLocation(['base']) && $checkPermission('master')" class="menu-options">
<li class="menu-option" @click="addToFavourites" v-if="fileInfoDetail && isFolder">
{{ isInFavourites ? $t('context_menu.remove_from_favourites') : $t('context_menu.add_to_favourites') }}
</li>
<li class="menu-option" @click="renameItem" v-if="fileInfoDetail">
{{ $t('context_menu.rename') }}
</li>
<li class="menu-option" @click="moveItem" v-if="fileInfoDetail">
{{ $t('context_menu.move') }}
</li>
<li class="menu-option" @click="shareItem" v-if="fileInfoDetail">
{{ fileInfoDetail.shared ? $t('context_menu.share_edit') : $t('context_menu.share') }}
</li>
<li class="menu-option" @click="downloadItem" v-if="! isFolder">
{{ $t('context_menu.download') }}
</li>
<li class="menu-option delete" @click="deleteItem" v-if="fileInfoDetail">
{{ $t('context_menu.delete') }}
</li>
</ul>
<div v-if="$isThisLocation(['base', 'latest']) && $checkPermission('master')" class="menu-options">
<ul class="menu-option-group" v-if="fileInfoDetail && 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">
<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">
<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">
<div class="icon">
<link-icon size="17"></link-icon>
</div>
<div class="text-label">
{{ fileInfoDetail.shared ? $t('context_menu.share_edit') : $t('context_menu.share') }}
</div>
</li>
<li class="menu-option delete" @click="deleteItem" v-if="fileInfoDetail">
<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>
</ul>
</div>
<!--Mobile for Base location with EDITOR permission-->
<ul v-if="$isThisLocation(['base', 'public']) && $checkPermission('editor')" class="menu-options">
<li class="menu-option" @click="renameItem" v-if="fileInfoDetail">
{{ $t('context_menu.rename') }}
</li>
<li class="menu-option" @click="moveItem" v-if="fileInfoDetail">
{{ $t('context_menu.move') }}
</li>
<li class="menu-option" @click="downloadItem" v-if="! isFolder">
{{ $t('context_menu.download') }}
</li>
</ul>
<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">
<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">
<div class="icon">
<corner-down-right-icon size="17"></corner-down-right-icon>
</div>
<div class="text-label">
{{ $t('context_menu.move') }}
</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>
</ul>
</div>
<!--Mobile for Base location with VISITOR permission-->
<ul v-if="$isThisLocation(['base', 'public']) && $checkPermission('visitor')" class="menu-options">
<li class="menu-option" @click="downloadItem" v-if="! isFolder">
{{ $t('context_menu.download') }}
</li>
</ul>
<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>
</ul>
</div>
</div>
</div>
</transition>
@@ -92,11 +218,37 @@
</template>
<script>
import ThumbnailItem from '@/components/Others/ThumbnailItem'
import {
CornerDownRightIcon,
DownloadCloudIcon,
FolderPlusIcon,
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,
ThumbnailItem,
LifeBuoyIcon,
Trash2Icon,
Edit2Icon,
TrashIcon,
LinkIcon,
StarIcon,
EyeIcon,
},
computed: {
...mapGetters(['fileInfoDetail', 'app']),
isInFavourites() {
@@ -194,10 +346,25 @@
</script>
<style scoped lang="scss">
@import "@assets/app.scss";
@import '@assets/vue-file-manager/_variables';
@import '@assets/vue-file-manager/_mixins';
.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.15);
background: rgba(0, 0, 0, 0.35);
position: absolute;
top: 0;
right: 0;
@@ -215,29 +382,46 @@
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;
box-shadow: $shadow;
background: white;
border-top-left-radius: 8px;
border-top-right-radius: 8px;
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(15);
@include font-size(14);
cursor: pointer;
width: 100%;
padding: 20px 10px;
padding: 17px 20px;
text-align: center;
border-bottom: 1px solid $light_mode_border;
&:last-child {
border: none;
@@ -253,12 +437,16 @@
}
.options {
background: $dark_mode_background;
.menu-options {
background: $dark_mode_background;
.menu-option {
.menu-option-group {
border-color: $dark_mode_border_color;
}
.menu-option {
color: $dark_mode_text_primary;
}
}
@@ -1,13 +1,9 @@
<template>
<div class="mobile-toolbar" v-if="$isMinimalScale()">
<div class="mobile-toolbar">
<!-- Go back-->
<div @click="goBack" class="go-back-button">
<FontAwesomeIcon
:class="{'is-visible': browseHistory.length > 0}"
class="icon-back"
icon="chevron-left"
></FontAwesomeIcon>
<chevron-left-icon size="17" :class="{'is-visible': browseHistory.length > 1}" class="icon-back"></chevron-left-icon>
</div>
<!--Folder Title-->
@@ -15,8 +11,8 @@
<!--More Actions-->
<div class="more-actions-button">
<div class="tap-area" @click="showSidebarMenu" v-if="$checkPermission('master')">
<FontAwesomeIcon icon="bars" v-if="isSmallAppSize"></FontAwesomeIcon>
<div class="tap-area" @click="showMobileNavigation" v-if="$checkPermission('master')">
<menu-icon size="17"></menu-icon>
</div>
</div>
</div>
@@ -26,15 +22,19 @@
import ToolbarButtonUpload from '@/components/FilesView/ToolbarButtonUpload'
import ToolbarButton from '@/components/FilesView/ToolbarButton'
import SearchBar from '@/components/FilesView/SearchBar'
import { MenuIcon, ChevronLeftIcon } from 'vue-feather-icons'
import {mapGetters} from 'vuex'
import {events} from '@/bus'
import {last} from 'lodash'
export default {
name: 'MobileToolBar',
components: {
ToolbarButtonUpload,
ChevronLeftIcon,
ToolbarButton,
SearchBar
SearchBar,
MenuIcon,
},
computed: {
...mapGetters([
@@ -49,36 +49,30 @@
directoryName() {
return this.currentFolder ? this.currentFolder.name : this.homeDirectory.name
},
previousFolder() {
const length = this.browseHistory.length - 2
return this.browseHistory[length] ? this.browseHistory[length] : this.homeDirectory
},
isSmallAppSize() {
return this.appSize === 'small'
}
},
data() {
return {
isSidebarMenu: false,
}
},
methods: {
showSidebarMenu() {
this.isSidebarMenu = ! this.isSidebarMenu
events.$emit('show:sidebar')
showMobileNavigation() {
events.$emit('show:mobile-navigation')
},
goBack() {
if (this.previousFolder.location === 'trash-root') {
let previousFolder = last(this.browseHistory)
if (previousFolder.location === 'trash-root') {
this.$store.dispatch('getTrash')
this.$store.commit('FLUSH_BROWSER_HISTORY')
} else if (previousFolder.location === 'shared') {
this.$store.dispatch('getShared')
} else {
if ( this.$isThisLocation('public') ) {
this.$store.dispatch('browseShared', [this.previousFolder, true])
this.$store.dispatch('browseShared', [{folder: previousFolder, back: true, init: false}])
} else {
this.$store.dispatch('getFolder', [this.previousFolder, true])
this.$store.dispatch('getFolder', [{folder: previousFolder, back: true, init: false}])
}
}
},
@@ -93,13 +87,13 @@
</script>
<style scoped lang="scss">
@import "@assets/app.scss";
@import '@assets/vue-file-manager/_variables';
@import '@assets/vue-file-manager/_mixins';
.mobile-toolbar {
background: white;
text-align: center;
display: flex;
display: none;
padding: 10px 0;
position: sticky;
top: 0;
@@ -121,6 +115,7 @@
cursor: pointer;
opacity: 0;
visibility: hidden;
margin-top: -2px;
&.is-visible {
opacity: 1;
@@ -154,10 +149,21 @@
position: absolute;
right: -10px;
top: -20px;
path, line, polyline, rect, circle {
stroke: $text;
}
}
}
}
@media only screen and (max-width: 960px) {
.mobile-toolbar {
display: flex;
}
}
@media (prefers-color-scheme: dark) {
.mobile-toolbar {
@@ -167,8 +173,11 @@
color: $dark_mode_text_primary;
}
.more-actions-button svg path {
fill: $dark_mode_text_primary;
.more-actions-button .tap-area {
path, line, polyline, rect, circle {
stroke: $dark_mode_text_primary;
}
}
}
}
@@ -12,7 +12,8 @@ export default {
</script>
<style scoped lang="scss">
@import "@assets/app.scss";
@import '@assets/vue-file-manager/_variables';
@import '@assets/vue-file-manager/_mixins';
.progress-bar {
width: 100%;
+54 -19
View File
@@ -1,5 +1,11 @@
<template>
<div class="search-bar">
<div class="icon" v-if="!isQuery">
<search-icon size="19"></search-icon>
</div>
<div class="icon" v-if="isQuery" @click="resetQuery">
<x-icon class="pointer" size="19"></x-icon>
</div>
<input
v-model="query"
class="query"
@@ -7,22 +13,21 @@
name="query"
:placeholder="$t('inputs.placeholder_search_files')"
/>
<div class="icon" v-if="!isQuery">
<FontAwesomeIcon icon="search"></FontAwesomeIcon>
</div>
<div class="icon" v-if="isQuery" @click="resetQuery">
<FontAwesomeIcon icon="times" class="pointer"></FontAwesomeIcon>
</div>
</div>
</template>
<script>
import { SearchIcon, XIcon } from 'vue-feather-icons'
import {mapGetters} from 'vuex'
import {debounce} from 'lodash'
import {events} from '@/bus'
export default {
name: 'SearchBar',
components: {
SearchIcon,
XIcon,
},
computed: {
...mapGetters(['currentFolder']),
isQuery() {
@@ -52,9 +57,9 @@
// Get back after delete query to previosly folder
if ( this.$isThisLocation('public') ) {
this.$store.dispatch('browseShared', [this.currentFolder, true])
this.$store.dispatch('browseShared', [{folder: this.currentFolder, back: true, init: false}])
} else {
this.$store.dispatch('getFolder', [this.currentFolder, true])
this.$store.dispatch('getFolder', [{folder: this.currentFolder, back: true, init: false}])
}
}
@@ -69,20 +74,20 @@
</script>
<style scoped lang="scss">
@import "@assets/app.scss";
@import '@assets/vue-file-manager/_variables';
@import '@assets/vue-file-manager/_mixins';
.search-bar {
position: relative;
input {
//width: 100%;
background: $light_background;
background: transparent;
border-radius: 8px;
outline: 0;
padding: 9px 20px;
font-weight: 100;
padding: 9px 20px 9px 43px;
font-weight: 400;
@include font-size(16);
min-width: 380px;
min-width: 175px;
transition: 0.15s all ease;
border: 1px solid white;
-webkit-appearance: none;
@@ -90,7 +95,7 @@
&::placeholder {
color: $text;
@include font-size(14);
font-weight: 400;
font-weight: 500;
}
&:focus {
@@ -108,8 +113,8 @@
.icon {
position: absolute;
top: 0;
right: 0;
padding: 10px 15px;
left: 0;
padding: 11px 15px;
.pointer {
cursor: pointer;
@@ -117,11 +122,41 @@
}
}
@media only screen and (max-width: 1024px) {
.search-bar input {
max-width: 190px;
padding-right: 0;
}
}
@media only screen and (max-width: 690px) {
.search-bar {
input {
min-width: initial;
width: 100%;
padding: 9px 20px 9px 30px;
&:focus {
border: 1px solid transparent;
box-shadow: none;
}
}
.icon {
padding: 11px 15px 11px 0;
}
}
}
@media (prefers-color-scheme: dark) {
.search-bar {
input {
background: $dark_mode_foreground;
border-color: $dark_mode_foreground;
border-color: transparent;
color: $dark_mode_text_primary;
&::placeholder {
color: $dark_mode_text_secondary;
@@ -11,7 +11,8 @@
</script>
<style scoped lang="scss">
@import "@assets/app.scss";
@import '@assets/vue-file-manager/_variables';
@import '@assets/vue-file-manager/_mixins';
#loading-bar-spinner.spinner {
left: 50%;
@@ -1,18 +1,36 @@
<template>
<button class="button" :title="action">
<FontAwesomeIcon class="icon" :icon="source"></FontAwesomeIcon>
<corner-down-right-icon v-if="source === 'move'" size="19"></corner-down-right-icon>
<folder-plus-icon v-if="source === 'folder-plus'" size="19"></folder-plus-icon>
<trash-2-icon v-if="source === 'trash'" size="19"></trash-2-icon>
<list-icon v-if="source === 'th-list'" size="19"></list-icon>
<info-icon v-if="source === 'info'" size="19"></info-icon>
<grid-icon v-if="source === 'th'" size="19"></grid-icon>
<link-icon v-if="source === 'share'" size="19"></link-icon>
</button>
</template>
<script>
import {FolderPlusIcon, Trash2Icon, GridIcon, ListIcon, InfoIcon, CornerDownRightIcon, LinkIcon} from 'vue-feather-icons'
export default {
name: 'ToolbarButton',
props: ['source', 'action']
props: ['source', 'action'],
components: {
CornerDownRightIcon,
FolderPlusIcon,
Trash2Icon,
ListIcon,
GridIcon,
InfoIcon,
LinkIcon,
},
}
</script>
<style scoped lang="scss">
@import "@assets/app.scss";
@import '@assets/vue-file-manager/_variables';
@import '@assets/vue-file-manager/_mixins';
.button {
height: 42px;
@@ -22,42 +40,36 @@
align-items: center;
justify-content: center;
padding: 0;
background: $light_background;
text-align: center;
cursor: pointer;
white-space: nowrap;
outline: none;
border: none;
.icon {
@include font-size(16);
}
@include transition(150ms);
background: transparent;
&:hover {
background: rgba($theme, .1);
background: $light_background;
/deep/ svg path {
@include transition;
fill: $theme;
}
}
&.active {
background: rgba($theme, .1);
/deep/ svg path {
fill: $theme;
path, line, polyline, rect, circle {
@include transition(150ms);
stroke: $theme;
}
}
}
@media (prefers-color-scheme: dark) {
.button {
background: $dark_mode_foreground;
}
.icon path {
fill: $dark_mode_text_primary;
.button {
background: transparent;
&:hover {
background: $dark_mode_foreground;
}
path, line, polyline, rect, circle {
stroke: $dark_mode_text_primary;
}
}
}
</style>
@@ -1,6 +1,6 @@
<template>
<label label="file" class="button file-input">
<FontAwesomeIcon class="icon" :icon="source"></FontAwesomeIcon>
<upload-cloud-icon size="17"></upload-cloud-icon>
<input
@change="emmitFiles"
v-show="false"
@@ -8,15 +8,19 @@
type="file"
name="files[]"
multiple
:disabled="$isThisLocation(['trash', 'trash-root'])"
/>
</label>
</template>
<script>
import { UploadCloudIcon } from 'vue-feather-icons'
export default {
name: 'ToolbarButtonUpload',
props: ['source', 'action'],
props: ['action'],
components: {
UploadCloudIcon,
},
methods: {
emmitFiles(e) {
this.$uploadFiles(e.target.files)
@@ -26,7 +30,8 @@
</script>
<style scoped lang="scss">
@import "@assets/app.scss";
@import '@assets/vue-file-manager/_variables';
@import '@assets/vue-file-manager/_mixins';
.button {
height: 42px;
@@ -36,7 +41,6 @@
align-items: center;
justify-content: center;
padding: 0;
background: $light_background;
text-align: center;
cursor: pointer;
white-space: nowrap;
@@ -44,26 +48,27 @@
border: none;
&:hover {
background: rgba($theme, .1);
background: $light_background;
/deep/ svg path {
@include transition;
fill: $theme;
path, line, polyline, rect, circle {
@include transition(150ms);
stroke: $theme;
}
}
.icon {
@include font-size(16);
}
}
@media (prefers-color-scheme: dark) {
.button {
background: $dark_mode_foreground;
}
.icon path {
fill: $dark_mode_text_primary;
.button {
background: transparent;
&:hover {
background: $dark_mode_foreground;
}
path, line, polyline, rect, circle {
stroke: $dark_mode_text_primary;
}
}
}
</style>
@@ -25,7 +25,8 @@
</script>
<style scoped lang="scss">
@import "@assets/app.scss";
@import '@assets/vue-file-manager/_variables';
@import '@assets/vue-file-manager/_mixins';
.info-panel-enter-active,
.info-panel-leave-active {