added prettier

This commit is contained in:
Čarodej
2022-02-01 12:21:38 +01:00
parent 5ae875233b
commit b38b532cbe
284 changed files with 25410 additions and 25338 deletions

View File

@@ -10,12 +10,7 @@
<p v-if="message" class="message">{{ message }}</p>
</div>
<div class="popup-actions">
<ButtonBase
@click.native="closePopup"
:button-style="buttonStyle"
class="action-confirm"
>{{ button }}
</ButtonBase>
<ButtonBase @click.native="closePopup" :button-style="buttonStyle" class="action-confirm">{{ button }} </ButtonBase>
</div>
</div>
</div>
@@ -23,182 +18,181 @@
</template>
<script>
import ButtonBase from "./ButtonBase";
import {events} from "../../bus";
import ButtonBase from './ButtonBase'
import { events } from '../../bus'
export default {
name: 'AlertPopup',
components: {
ButtonBase
},
data() {
return {
isVisibleWrapper: false,
buttonStyle: undefined,
message: undefined,
title: undefined,
button: undefined,
emoji: undefined,
}
},
methods: {
closePopup() {
events.$emit('popup:close')
}
},
mounted() {
// Show alert
events.$on('alert:open', args => {
this.isVisibleWrapper = true
this.title = args.title
this.message = args.message
this.button = this.$t('alerts.error_confirm')
this.emoji = '😢😢😢'
this.buttonStyle = 'danger-solid'
if (args.emoji) {
this.emoji = args.emoji
}
if (args.buttonStyle) {
this.buttonStyle = args.buttonStyle
}
if (args.button) {
this.button = args.button
}
})
// Show alert
events.$on('success:open', args => {
this.isVisibleWrapper = true
this.title = args.title
this.message = args.message
this.button = this.$t('alerts.success_confirm')
this.emoji = '🥳🥳🥳'
this.buttonStyle = 'theme'
if (args.emoji) {
this.emoji = args.emoji
}
})
// Close popup
events.$on('popup:close', () => {
this.isVisibleWrapper = false
})
export default {
name: 'AlertPopup',
components: {
ButtonBase,
},
data() {
return {
isVisibleWrapper: false,
buttonStyle: undefined,
message: undefined,
title: undefined,
button: undefined,
emoji: undefined,
}
}
},
methods: {
closePopup() {
events.$emit('popup:close')
},
},
mounted() {
// Show alert
events.$on('alert:open', (args) => {
this.isVisibleWrapper = true
this.title = args.title
this.message = args.message
this.button = this.$t('alerts.error_confirm')
this.emoji = '😢😢😢'
this.buttonStyle = 'danger-solid'
if (args.emoji) {
this.emoji = args.emoji
}
if (args.buttonStyle) {
this.buttonStyle = args.buttonStyle
}
if (args.button) {
this.button = args.button
}
})
// Show alert
events.$on('success:open', (args) => {
this.isVisibleWrapper = true
this.title = args.title
this.message = args.message
this.button = this.$t('alerts.success_confirm')
this.emoji = '🥳🥳🥳'
this.buttonStyle = 'theme'
if (args.emoji) {
this.emoji = args.emoji
}
})
// Close popup
events.$on('popup:close', () => {
this.isVisibleWrapper = false
})
},
}
</script>
<style scoped lang="scss">
@import '../../../sass/vuefilemanager/variables';
@import '../../../sass/vuefilemanager/mixins';
@import '../../../sass/vuefilemanager/variables';
@import '../../../sass/vuefilemanager/mixins';
.popup {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
z-index: 45;
overflow: auto;
height: 100%;
.popup {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
z-index: 45;
overflow: auto;
height: 100%;
}
.popup-wrapper {
z-index: 12;
position: absolute;
left: 0;
right: 0;
max-width: 480px;
top: 50%;
transform: translateY(-50%) scale(1);
margin: 0 auto;
padding: 20px;
box-shadow: $light_mode_popup_shadow;
border-radius: 8px;
text-align: center;
background: white;
}
.popup-image {
margin-bottom: 30px;
.emoji {
@include font-size(56);
line-height: 1;
}
}
.popup-content {
.title {
@include font-size(22);
text-transform: uppercase;
font-weight: 800;
color: $text;
}
.message {
@include font-size(16);
color: #333;
margin-top: 5px;
}
}
.popup-actions {
margin-top: 30px;
.action-confirm {
width: 100%;
}
}
@media only screen and (max-width: 690px) {
.popup-wrapper {
z-index: 12;
position: absolute;
left: 0;
right: 0;
max-width: 480px;
top: 50%;
transform: translateY(-50%) scale(1);
margin: 0 auto;
padding: 20px;
box-shadow: $light_mode_popup_shadow;
border-radius: 8px;
text-align: center;
background: white;
padding: 40px 20px 20px;
left: 15px;
right: 15px;
}
}
.popup-image {
margin-bottom: 30px;
.emoji {
@include font-size(56);
line-height: 1;
}
.dark {
.popup-wrapper {
background: $dark_mode_foreground;
}
.popup-content {
.title {
@include font-size(22);
text-transform: uppercase;
font-weight: 800;
color: $text;
color: $dark_mode_text_primary;
}
.message {
@include font-size(16);
color: #333;
margin-top: 5px;
color: $dark_mode_text_secondary;
}
}
}
.popup-actions {
margin-top: 30px;
// Animations
.popup-enter-active {
animation: popup-in 0.35s 0.15s ease both;
}
.action-confirm {
width: 100%;
}
.popup-leave-active {
animation: popup-in 0.15s ease reverse;
}
@keyframes popup-in {
0% {
opacity: 0;
transform: scale(0.7);
}
@media only screen and (max-width: 690px) {
.popup-wrapper {
padding: 40px 20px 20px;
left: 15px;
right: 15px;
}
}
.dark {
.popup-wrapper {
background: $dark_mode_foreground;
}
.popup-content {
.title {
color: $dark_mode_text_primary;
}
.message {
color: $dark_mode_text_secondary;
}
}
}
// Animations
.popup-enter-active {
animation: popup-in 0.35s 0.15s ease both;
}
.popup-leave-active {
animation: popup-in 0.15s ease reverse;
}
@keyframes popup-in {
0% {
opacity: 0;
transform: scale(0.7);
}
100% {
opacity: 1;
transform: scale(1);
}
100% {
opacity: 1;
transform: scale(1);
}
}
</style>

View File

@@ -2,129 +2,130 @@
<button class="button-base" :class="buttonStyle" type="button">
<div v-if="loading" class="icon">
<refresh-cw-icon size="16" class="sync-alt" />
</div>
</div>
<div class="content">
<slot v-if="! loading"></slot>
<slot v-if="!loading"></slot>
</div>
</button>
</template>
<script>
import { RefreshCwIcon } from 'vue-feather-icons'
import { RefreshCwIcon } from 'vue-feather-icons'
export default {
name: 'ButtonBase',
props: ['buttonStyle', 'loading'],
components: {
RefreshCwIcon,
}
}
export default {
name: 'ButtonBase',
props: ['buttonStyle', 'loading'],
components: {
RefreshCwIcon,
},
}
</script>
<style scoped lang="scss">
@import '../../../sass/vuefilemanager/variables';
@import '../../../sass/vuefilemanager/mixins';
@import '../../../sass/vuefilemanager/variables';
@import '../../../sass/vuefilemanager/mixins';
.button-base {
@include font-size(15);
font-weight: 700;
cursor: pointer;
transition: 0.15s all ease;
border-radius: 8px;
border: 0;
padding: 10px 28px;
white-space: nowrap;
display: flex;
align-items: center;
justify-content: center;
.icon {
line-height: 1;
margin-right: 10px;
}
&:active {
transform: scale(0.95);
}
&.theme-solid {
.content {
color: white;
}
}
&.danger {
background: rgba($danger, 0.1);
.content {
color: $danger;
}
polyline,
path {
stroke: $danger;
}
}
&.danger-solid {
background: $danger;
.content {
color: white;
}
polyline,
path {
stroke: white;
}
}
&.secondary {
background: $light_background;
.content {
color: $text;
}
polyline,
path {
stroke: $text;
}
}
}
.sync-alt {
animation: spin 1s linear infinite;
}
@keyframes spin {
0% {
transform: rotate(0);
}
100% {
transform: rotate(360deg);
}
}
.dark {
.button-base {
@include font-size(15);
font-weight: 700;
cursor: pointer;
transition: 0.15s all ease;
border-radius: 8px;
border: 0;
padding: 10px 28px;
white-space: nowrap;
display: flex;
align-items: center;
justify-content: center;
.icon {
line-height: 1;
margin-right: 10px;
}
&:active {
transform: scale(0.95);
}
&.theme-solid {
.content {
color: white;
}
}
&.danger {
background: rgba($danger, .1);
.content {
color: $danger;
}
polyline, path {
stroke: $danger;
}
}
&.danger-solid {
background: $danger;
.content {
color: white;
}
polyline, path {
stroke: white;
}
}
&.secondary {
background: $light_background;
background: $dark_mode_foreground;
.content {
color: $text;
color: $dark_mode_text_primary;
}
polyline, path {
stroke: $text;
polyline,
path {
color: inherit;
}
}
}
.sync-alt {
animation: spin 1s linear infinite;
}
@keyframes spin {
0% {
transform: rotate(0);
}
100% {
transform: rotate(360deg);
}
}
.dark {
.button-base {
&.secondary {
background: $dark_mode_foreground;
.content {
color: $dark_mode_text_primary;
}
polyline, path {
color: inherit;
}
}
}
.popup-wrapper {
.button-base.secondary {
background: lighten($dark_mode_foreground, 3%);
}
.popup-wrapper {
.button-base.secondary {
background: lighten($dark_mode_foreground, 3%);
}
}
}
</style>

View File

@@ -1,56 +1,48 @@
<template>
<label :class="buttonStyle" label="file" class="button file-input button-base">
<slot></slot>
<input
accept="*"
v-show="false"
@change="emmitFiles"
id="file"
type="file"
name="files[]"
multiple
/>
<input accept="*" v-show="false" @change="emmitFiles" id="file" type="file" name="files[]" multiple />
</label>
</template>
<script>
export default {
name: 'ButtonBase',
props: ['buttonStyle'],
data() {
return {
files: undefined
}
},
methods: {
emmitFiles(e) {
this.$uploadFiles(e.target.files)
}
export default {
name: 'ButtonBase',
props: ['buttonStyle'],
data() {
return {
files: undefined,
}
}
},
methods: {
emmitFiles(e) {
this.$uploadFiles(e.target.files)
},
},
}
</script>
<style scoped lang="scss">
@import '../../../sass/vuefilemanager/variables';
@import '../../../sass/vuefilemanager/mixins';
@import '../../../sass/vuefilemanager/variables';
@import '../../../sass/vuefilemanager/mixins';
.button-base {
@include font-size(15);
font-weight: 700;
cursor: pointer;
transition: 0.15s all ease;
border-radius: 8px;
border: 0;
padding: 10px 28px;
display: inline-block;
.button-base {
@include font-size(15);
font-weight: 700;
cursor: pointer;
transition: 0.15s all ease;
border-radius: 8px;
border: 0;
padding: 10px 28px;
display: inline-block;
&:active {
transform: scale(0.95);
}
&.secondary {
color: $text;
background: $light_background;
}
&:active {
transform: scale(0.95);
}
&.secondary {
color: $text;
background: $light_background;
}
}
</style>

View File

@@ -1,39 +1,40 @@
<template>
<div>
<div
class="w-5 h-5 flex items-center justify-center rounded-md"
:class="{'bg-theme': isClicked, 'dark:bg-dark-foreground bg-light-background': !isClicked}"
@click="changeState"
>
<CheckIcon v-if="isClicked" class="vue-feather text-white" size="17" />
</div>
</div>
<div>
<div
class="flex h-5 w-5 items-center justify-center rounded-md"
:class="{
'bg-theme': isClicked,
'bg-light-background dark:bg-dark-foreground': !isClicked,
}"
@click="changeState"
>
<CheckIcon v-if="isClicked" class="vue-feather text-white" size="17" />
</div>
</div>
</template>
<script>
import {CheckIcon} from 'vue-feather-icons'
import { CheckIcon } from 'vue-feather-icons'
export default {
name: 'CheckBox',
props: [
'isClicked'
],
components: {
CheckIcon
},
data() {
return {
isSwitched: undefined
}
},
methods: {
changeState() {
this.isSwitched = ! this.isSwitched
this.$emit('input', this.isSwitched)
}
},
mounted() {
this.isSwitched = this.isClicked
}
name: 'CheckBox',
props: ['isClicked'],
components: {
CheckIcon,
},
data() {
return {
isSwitched: undefined,
}
},
methods: {
changeState() {
this.isSwitched = !this.isSwitched
this.$emit('input', this.isSwitched)
},
},
mounted() {
this.isSwitched = this.isClicked
},
}
</script>

View File

@@ -1,116 +1,110 @@
<template>
<div
v-show="isVisible"
:style="{top: positionY + 'px', left: positionX + 'px'}"
@click="closeAndResetContextMenu"
class="absolute w-60 shadow-lg rounded-xl z-20 dark:bg-2x-dark-foreground bg-white overflow-hidden"
ref="contextmenu"
>
v-show="isVisible"
:style="{ top: positionY + 'px', left: positionX + 'px' }"
@click="closeAndResetContextMenu"
class="absolute z-20 w-60 overflow-hidden rounded-xl bg-white shadow-lg dark:bg-2x-dark-foreground"
ref="contextmenu"
>
<div id="menu-list" class="w-full">
<!--Show empty select contextmenu-->
<slot name="empty-select" v-if="!item" />
<!--Show empty select contextmenu-->
<slot name="empty-select" v-if="! item" />
<!--Show single select contextmenu-->
<slot name="single-select" v-if="isMultiSelectContextMenu" />
<!--Show single select contextmenu-->
<slot name="single-select" v-if="isMultiSelectContextMenu" />
<!--Show multiple select contextmenu-->
<slot name="multiple-select" v-if="! isMultiSelectContextMenu" />
<!--Show multiple select contextmenu-->
<slot name="multiple-select" v-if="!isMultiSelectContextMenu" />
</div>
</div>
</template>
<script>
import {events} from "../../bus";
import {mapGetters} from 'vuex'
import { events } from '../../bus'
import { mapGetters } from 'vuex'
export default {
name: 'ContextMenu',
computed: {
...mapGetters([
'clipboard',
'user',
]),
isMultiSelectContextMenu() {
// If is context Menu open on multi selected items open just options for the multi selected items
if (this.clipboard.length > 1 && this.clipboard.includes(this.item))
return false
name: 'ContextMenu',
computed: {
...mapGetters(['clipboard', 'user']),
isMultiSelectContextMenu() {
// If is context Menu open on multi selected items open just options for the multi selected items
if (this.clipboard.length > 1 && this.clipboard.includes(this.item)) return false
// If is context Menu open for the non selected item open options for the single item
if (this.clipboard.length < 2 || !this.clipboard.includes(this.item))
return true
},
},
data() {
return {
item: undefined,
isVisible: false,
positionX: 0,
positionY: 0
}
},
methods: {
closeAndResetContextMenu() {
// Close context menu
this.isVisible = false
// If is context Menu open for the non selected item open options for the single item
if (this.clipboard.length < 2 || !this.clipboard.includes(this.item)) return true
},
},
data() {
return {
item: undefined,
isVisible: false,
positionX: 0,
positionY: 0,
}
},
methods: {
closeAndResetContextMenu() {
// Close context menu
this.isVisible = false
// Reset item container
this.item = undefined
},
showContextMenu(event) {
let parent = document.getElementById('menu-list')
let nodesSameClass = parent.getElementsByClassName('menu-option')
// Reset item container
this.item = undefined
},
showContextMenu(event) {
let parent = document.getElementById('menu-list')
let nodesSameClass = parent.getElementsByClassName('menu-option')
let VerticalOffsetArea = nodesSameClass.length * 50
let HorizontalOffsetArea = 190
let VerticalOffsetArea = nodesSameClass.length * 50
let HorizontalOffsetArea = 190
let container = document.getElementById('file-view')
let container = document.getElementById('file-view')
let offset = container.getClientRects()[0]
let offset = container.getClientRects()[0]
let x = event.clientX - offset.left
let y = event.clientY - offset.top
let x = event.clientX - offset.left
let y = event.clientY - offset.top
// Set position Y
if (container.offsetHeight - y < VerticalOffsetArea) {
this.positionY = y - VerticalOffsetArea
} else {
this.positionY = y
}
// Set position Y
if (container.offsetHeight - y < VerticalOffsetArea) {
this.positionY = y - VerticalOffsetArea
} else {
this.positionY = y
}
// Set position X
if (container.offsetWidth - x < HorizontalOffsetArea) {
this.positionX = x - HorizontalOffsetArea
} else {
this.positionX = x
}
// Set position X
if (container.offsetWidth - x < HorizontalOffsetArea) {
this.positionX = x - HorizontalOffsetArea
} else {
this.positionX = x
}
// Show context menu
this.isVisible = true
}
},
created() {
events.$on('context-menu:hide', () => this.closeAndResetContextMenu())
// Show context menu
this.isVisible = true
},
},
created() {
events.$on('context-menu:hide', () => this.closeAndResetContextMenu())
events.$on('context-menu:show', (event, item) => {
// Store item
this.item = item
events.$on('context-menu:show', (event, item) => {
// Store item
this.item = item
// Show context menu
setTimeout(() => this.showContextMenu(event, item), 10)
})
// Show context menu
setTimeout(() => this.showContextMenu(event, item), 10)
})
events.$on('context-menu:current-folder', folder => {
this.item = folder
events.$on('context-menu:current-folder', (folder) => {
this.item = folder
this.isVisible = ! this.isVisible
this.isVisible = !this.isVisible
if (this.isVisible) {
let container = document.getElementById('folder-actions')
if (this.isVisible) {
let container = document.getElementById('folder-actions')
this.positionX = container.offsetLeft
}
})
}
this.positionX = container.offsetLeft
}
})
},
}
</script>

View File

@@ -1,380 +1,399 @@
<template>
<div id="desktop-toolbar" class="lg:block hidden">
<div id="desktop-toolbar" class="hidden lg:block">
<div class="toolbar-wrapper">
<div @click="goBack" class="location">
<div v-if="! isVisibleNavigationBars" @click="toggleNavigationBars" class="mr-2">
<menu-icon size="17" />
</div>
<div @click="goBack" class="location">
<div v-if="!isVisibleNavigationBars" @click="toggleNavigationBars" class="mr-2">
<menu-icon size="17" />
</div>
<chevron-left-icon :class="{'opacity-0 -translate-x-3': ! currentFolder, 'opacity-100 translate-x-0': currentFolder }" class="icon-back transform transition-all duration-200" size="17" />
<chevron-left-icon
:class="{
'-translate-x-3 opacity-0': !currentFolder,
'translate-x-0 opacity-100': currentFolder,
}"
class="icon-back transform transition-all duration-200"
size="17"
/>
<span :class="{'-translate-x-4': ! currentFolder}" class="location-title transform transition-all duration-200">
{{ $getCurrentLocationName() }}
</span>
<span :class="{ '-translate-x-4': !currentFolder }" class="location-title transform transition-all duration-200">
{{ $getCurrentLocationName() }}
</span>
<span :class="{'-translate-x-4 opacity-0': ! currentFolder, 'translate-x-0 opacity-100': currentFolder}" @click.stop="folderActions" class="transform location-more group transition-all duration-200" id="folder-actions">
<more-horizontal-icon size="14" class="icon-more group-hover-text-theme" />
</span>
</div>
<span
:class="{
'-translate-x-4 opacity-0': !currentFolder,
'translate-x-0 opacity-100': currentFolder,
}"
@click.stop="folderActions"
class="location-more group transform transition-all duration-200"
id="folder-actions"
>
<more-horizontal-icon size="14" class="icon-more group-hover-text-theme" />
</span>
</div>
<ToolbarWrapper>
<ToolbarWrapper>
<!--Search bar-->
<ToolbarGroup class="ml-0">
<SearchBar class="hidden lg:block" />
</ToolbarGroup>
<!--Search bar-->
<ToolbarGroup class="ml-0">
<SearchBar class="lg:block hidden" />
</ToolbarGroup>
<!--Create button for all pages except SharedWithMe-->
<ToolbarGroup v-if="$checkPermission(['master', 'editor']) && !$isThisRoute($route, ['SharedWithMe'])">
<span class="block lg:hidden">
<ToolbarButton @click.stop.native="$openSpotlight()" source="search" :action="$t('Search files or folders')" />
</span>
<!--Create button for all pages except SharedWithMe-->
<ToolbarGroup v-if="$checkPermission(['master', 'editor']) && ! $isThisRoute($route, ['SharedWithMe'])">
<PopoverWrapper>
<ToolbarButton @click.stop.native="showCreateMenu" source="cloud-plus" :action="$t('actions.create')" />
<span class="lg:hidden block">
<ToolbarButton @click.stop.native="$openSpotlight()" source="search" :action="$t('Search files or folders')" />
</span>
<PopoverItem name="desktop-create" side="left">
<OptionGroup :class="{ 'is-inactive': canUploadInView }">
<OptionUpload :title="$t('actions.upload')" type="file" />
<OptionUpload :title="$t('actions.upload_folder')" type="folder" />
</OptionGroup>
<OptionGroup>
<Option @click.stop.native="$createTeamFolder" :title="$t('Create Team Folder')" icon="users" />
<Option
@click.stop.native="$createFolder"
:class="{
'is-inactive': canCreateFolderInView || isTeamFolderHomepage,
}"
:title="$t('actions.create_folder')"
icon="folder-plus"
/>
</OptionGroup>
</PopoverItem>
</PopoverWrapper>
</ToolbarGroup>
<PopoverWrapper>
<ToolbarButton @click.stop.native="showCreateMenu" source="cloud-plus" :action="$t('actions.create')" />
<!--Create button for shared with me page-->
<ToolbarGroup v-if="$isThisRoute($route, ['SharedWithMe'])">
<span class="block lg:hidden">
<ToolbarButton @click.stop.native="$openSpotlight()" source="search" :action="$t('Search files or folders')" />
</span>
<PopoverItem name="desktop-create" side="left">
<OptionGroup :class="{'is-inactive': canUploadInView }">
<OptionUpload :title="$t('actions.upload')" type="file" />
<OptionUpload :title="$t('actions.upload_folder')" type="folder" />
</OptionGroup>
<OptionGroup>
<Option @click.stop.native="$createTeamFolder" :title="$t('Create Team Folder')" icon="users" />
<Option @click.stop.native="$createFolder" :class="{'is-inactive': canCreateFolderInView || isTeamFolderHomepage }" :title="$t('actions.create_folder')" icon="folder-plus" />
</OptionGroup>
</PopoverItem>
</PopoverWrapper>
</ToolbarGroup>
<PopoverWrapper>
<ToolbarButton @click.stop.native="showCreateMenu" source="cloud-plus" :class="{ 'is-inactive': !canEdit }" :action="$t('actions.create')" />
<!--Create button for shared with me page-->
<ToolbarGroup v-if="$isThisRoute($route, ['SharedWithMe'])">
<span class="lg:hidden block">
<ToolbarButton @click.stop.native="$openSpotlight()" source="search" :action="$t('Search files or folders')" />
</span>
<PopoverItem name="desktop-create" side="left">
<OptionGroup>
<OptionUpload
:class="{
'is-inactive': canUploadInView || isSharedWithMeHomepage,
}"
:title="$t('actions.upload')"
/>
</OptionGroup>
<OptionGroup>
<Option
@click.stop.native="$createFolder"
:class="{
'is-inactive': canCreateFolderInView || isSharedWithMeHomepage,
}"
:title="$t('actions.create_folder')"
icon="folder-plus"
/>
</OptionGroup>
</PopoverItem>
</PopoverWrapper>
</ToolbarGroup>
<PopoverWrapper>
<ToolbarButton @click.stop.native="showCreateMenu" source="cloud-plus" :class="{'is-inactive': ! canEdit}" :action="$t('actions.create')" />
<!--File Controls-->
<ToolbarGroup v-if="$checkPermission(['master', 'editor']) || ($isMobile() && $isThisRoute($route, ['SharedWithMe', 'TeamFolders']))">
<!--Team Heads-->
<PopoverWrapper v-if="$isThisRoute($route, ['TeamFolders', 'SharedWithMe'])">
<TeamMembersButton
@click.stop.native="showTeamFolderMenu"
size="32"
class="cursor-pointer rounded-lg py-0.5 pl-2 pr-0.5 hover:bg-light-background dark:hover:bg-dark-foreground"
/>
<PopoverItem name="desktop-create" side="left">
<OptionGroup>
<OptionUpload :class="{'is-inactive': canUploadInView || isSharedWithMeHomepage }" :title="$t('actions.upload')" />
</OptionGroup>
<OptionGroup>
<Option @click.stop.native="$createFolder" :class="{'is-inactive': canCreateFolderInView || isSharedWithMeHomepage }" :title="$t('actions.create_folder')" icon="folder-plus" />
</OptionGroup>
</PopoverItem>
</PopoverWrapper>
</ToolbarGroup>
<PopoverItem name="team-folder" side="left">
<TeamFolderPreview />
<!--File Controls-->
<ToolbarGroup v-if="$checkPermission(['master', 'editor']) || ($isMobile() && $isThisRoute($route, ['SharedWithMe', 'TeamFolders']))">
<OptionGroup v-if="$isThisRoute($route, ['TeamFolders'])">
<Option @click.native="$updateTeamFolder(teamFolder)" :title="$t('Edit Members')" icon="rename" />
<Option @click.native="$dissolveTeamFolder(teamFolder)" :title="$t('Dissolve Team')" icon="trash" />
</OptionGroup>
<!--Team Heads-->
<PopoverWrapper v-if="$isThisRoute($route, ['TeamFolders', 'SharedWithMe'])">
<TeamMembersButton @click.stop.native="showTeamFolderMenu" size="32" class="dark:hover:bg-dark-foreground hover:bg-light-background rounded-lg cursor-pointer py-0.5 pl-2 pr-0.5" />
<OptionGroup v-if="$isThisRoute($route, ['SharedWithMe'])">
<Option @click.native="$detachMeFromTeamFolder(teamFolder)" :title="$t('Leave the Team Folder')" icon="user-minus" />
</OptionGroup>
</PopoverItem>
</PopoverWrapper>
<PopoverItem name="team-folder" side="left">
<TeamFolderPreview />
<!--Item actions-->
<span v-if="!$isMobile()" class="whitespace-nowrap">
<ToolbarButton
v-if="canShowConvertToTeamFolder"
@click.native="$convertAsTeamFolder(clipboard[0])"
:class="{
'is-inactive': !canCreateTeamFolderInView,
}"
source="user-plus"
:action="$t('actions.convert_into_team_folder')"
/>
<ToolbarButton
v-if="!$isThisRoute($route, ['SharedWithMe', 'Public'])"
@click.native="$shareFileOrFolder(clipboard[0])"
:class="{ 'is-inactive': canShareInView }"
source="share"
:action="$t('actions.share')"
/>
<OptionGroup v-if="$isThisRoute($route, ['TeamFolders'])">
<Option @click.native="$updateTeamFolder(teamFolder)" :title="$t('Edit Members')" icon="rename" />
<Option @click.native="$dissolveTeamFolder(teamFolder)" :title="$t('Dissolve Team')" icon="trash" />
</OptionGroup>
<ToolbarButton
@click.native="$moveFileOrFolder(clipboard[0])"
:class="{
'is-inactive': canMoveInView && !canEdit,
}"
source="move"
:action="$t('actions.move')"
/>
<ToolbarButton
@click.native="$deleteFileOrFolder(clipboard[0])"
:class="{
'is-inactive': canDeleteInView && !canEdit,
}"
source="trash"
:action="$t('actions.delete')"
/>
</span>
</ToolbarGroup>
<OptionGroup v-if="$isThisRoute($route, ['SharedWithMe'])">
<Option @click.native="$detachMeFromTeamFolder(teamFolder)" :title="$t('Leave the Team Folder')" icon="user-minus" />
</OptionGroup>
</PopoverItem>
</PopoverWrapper>
<!--Item actions-->
<span v-if="! $isMobile()" class="whitespace-nowrap">
<ToolbarButton v-if="canShowConvertToTeamFolder" @click.native="$convertAsTeamFolder(clipboard[0])" :class="{'is-inactive': ! canCreateTeamFolderInView }" source="user-plus" :action="$t('actions.convert_into_team_folder')" />
<ToolbarButton v-if="! $isThisRoute($route, ['SharedWithMe', 'Public'])" @click.native="$shareFileOrFolder(clipboard[0])" :class="{'is-inactive': canShareInView }" source="share" :action="$t('actions.share')" />
<ToolbarButton @click.native="$moveFileOrFolder(clipboard[0])" :class="{'is-inactive': canMoveInView && ! canEdit }" source="move" :action="$t('actions.move')" />
<ToolbarButton @click.native="$deleteFileOrFolder(clipboard[0])" :class="{'is-inactive': canDeleteInView && ! canEdit }" source="trash" :action="$t('actions.delete')" />
</span>
</ToolbarGroup>
<!--View Controls-->
<ToolbarGroup>
<PopoverWrapper>
<ToolbarButton @click.stop.native="showSortingMenu" source="preview-sorting" :action="$t('actions.sorting_view')" />
<PopoverItem name="desktop-sorting" side="left">
<FileSortingOptions />
</PopoverItem>
</PopoverWrapper>
<!--View Controls-->
<ToolbarGroup>
<PopoverWrapper>
<ToolbarButton @click.stop.native="showSortingMenu" source="preview-sorting" :action="$t('actions.sorting_view')" />
<PopoverItem name="desktop-sorting" side="left">
<FileSortingOptions />
</PopoverItem>
</PopoverWrapper>
<ToolbarButton @click.native="$store.dispatch('fileInfoToggle')" :action="$t('actions.info_panel')" source="info" />
</ToolbarGroup>
</ToolbarWrapper>
</ToolbarGroup>
</ToolbarWrapper>
</div>
<UploadProgress />
<UploadProgress />
</div>
</template>
<script>
import FileSortingOptions from "./FileSortingOptions";
import UploadProgress from "./UploadProgress";
import PopoverWrapper from "../Desktop/PopoverWrapper";
import ToolbarWrapper from "../Desktop/ToolbarWrapper";
import ToolbarButton from "./ToolbarButton";
import OptionUpload from "./OptionUpload";
import ToolbarGroup from "../Desktop/ToolbarGroup";
import OptionGroup from "./OptionGroup";
import TeamMembersButton from "../Teams/Components/TeamMembersButton"
import PopoverItem from "../Desktop/PopoverItem";
import TeamFolderPreview from "../Teams/Components/TeamFolderPreview"
import {MenuIcon, ChevronLeftIcon, MoreHorizontalIcon} from 'vue-feather-icons'
import SearchBar from "./SearchBar";
import Option from "./Option";
import {events} from "../../bus";
import {mapGetters} from 'vuex'
import FileSortingOptions from './FileSortingOptions'
import UploadProgress from './UploadProgress'
import PopoverWrapper from '../Desktop/PopoverWrapper'
import ToolbarWrapper from '../Desktop/ToolbarWrapper'
import ToolbarButton from './ToolbarButton'
import OptionUpload from './OptionUpload'
import ToolbarGroup from '../Desktop/ToolbarGroup'
import OptionGroup from './OptionGroup'
import TeamMembersButton from '../Teams/Components/TeamMembersButton'
import PopoverItem from '../Desktop/PopoverItem'
import TeamFolderPreview from '../Teams/Components/TeamFolderPreview'
import { MenuIcon, ChevronLeftIcon, MoreHorizontalIcon } from 'vue-feather-icons'
import SearchBar from './SearchBar'
import Option from './Option'
import { events } from '../../bus'
import { mapGetters } from 'vuex'
export default {
name: 'DesktopToolbar',
components: {
TeamMembersButton,
FileSortingOptions,
MoreHorizontalIcon,
TeamFolderPreview,
ChevronLeftIcon,
ToolbarWrapper,
UploadProgress,
PopoverWrapper,
ToolbarButton,
OptionUpload,
ToolbarGroup,
OptionGroup,
PopoverItem,
SearchBar,
MenuIcon,
Option,
},
computed: {
...mapGetters([
'isVisibleNavigationBars',
'currentTeamFolder',
'currentFolder',
'sharedDetail',
'clipboard',
'user',
]),
canEdit() {
if (this.currentTeamFolder && this.user && this.clipboard[0]) {
let member = this.currentTeamFolder.data.relationships.members.data.find(member => member.data.id === this.user.data.id)
export default {
name: 'DesktopToolbar',
components: {
TeamMembersButton,
FileSortingOptions,
MoreHorizontalIcon,
TeamFolderPreview,
ChevronLeftIcon,
ToolbarWrapper,
UploadProgress,
PopoverWrapper,
ToolbarButton,
OptionUpload,
ToolbarGroup,
OptionGroup,
PopoverItem,
SearchBar,
MenuIcon,
Option,
},
computed: {
...mapGetters(['isVisibleNavigationBars', 'currentTeamFolder', 'currentFolder', 'sharedDetail', 'clipboard', 'user']),
canEdit() {
if (this.currentTeamFolder && this.user && this.clipboard[0]) {
let member = this.currentTeamFolder.data.relationships.members.data.find((member) => member.data.id === this.user.data.id)
return member.data.attributes.permission === 'can-edit'
}
return member.data.attributes.permission === 'can-edit'
}
return false
},
teamFolder() {
return this.currentTeamFolder
? this.currentTeamFolder
: this.clipboard[0]
},
isNotHomepage() {
if (this.$isThisRoute(this.$route, ['Public'])) {
return this.sharedDetail && this.sharedDetail.data.attributes.item_id === this.$route.params.id
}
return false
},
teamFolder() {
return this.currentTeamFolder ? this.currentTeamFolder : this.clipboard[0]
},
isNotHomepage() {
if (this.$isThisRoute(this.$route, ['Public'])) {
return this.sharedDetail && this.sharedDetail.data.attributes.item_id === this.$route.params.id
}
return this.$route.params.id
},
isTeamFolderHomepage() {
return this.$isThisRoute(this.$route, ['TeamFolders'])
&& ! this.$route.params.id
},
isSharedWithMeHomepage() {
return this.$isThisRoute(this.$route, ['SharedWithMe'])
&& ! this.$route.params.id
},
canCreateFolderInView() {
return ! this.$isThisRoute(this.$route, ['Files', 'Public', 'TeamFolders', 'SharedWithMe'])
},
canShowConvertToTeamFolder() {
return this.$isThisRoute(this.$route, ['Files', 'MySharedItems'])
},
canUploadInView() {
return ! this.$isThisRoute(this.$route, ['Files', 'Public', 'TeamFolders', 'SharedWithMe'])
},
canDeleteInView() {
let routes = [
'TeamFolders',
'SharedWithMe',
'RecentUploads',
'MySharedItems',
'Trash',
'Public',
'Files',
]
return !this.$isThisRoute(this.$route, routes)
|| this.clipboard.length === 0
},
canMoveInView() {
let routes = [
'SharedWithMe',
'RecentUploads',
'MySharedItems',
'Public',
'Files',
'TeamFolders',
]
return ! this.$isThisRoute(this.$route, routes)
|| this.clipboard.length === 0
},
canShareInView() {
let routes = [
'TeamFolders',
'RecentUploads',
'MySharedItems',
'Public',
'Files',
]
return ! this.$isThisRoute(this.$route, routes)
|| this.clipboard.length > 1
|| this.clipboard.length === 0
},
canCreateTeamFolderInView() {
let routes = [
'MySharedItems',
'Files',
]
return this.$route.params.id
},
isTeamFolderHomepage() {
return this.$isThisRoute(this.$route, ['TeamFolders']) && !this.$route.params.id
},
isSharedWithMeHomepage() {
return this.$isThisRoute(this.$route, ['SharedWithMe']) && !this.$route.params.id
},
canCreateFolderInView() {
return !this.$isThisRoute(this.$route, ['Files', 'Public', 'TeamFolders', 'SharedWithMe'])
},
canShowConvertToTeamFolder() {
return this.$isThisRoute(this.$route, ['Files', 'MySharedItems'])
},
canUploadInView() {
return !this.$isThisRoute(this.$route, ['Files', 'Public', 'TeamFolders', 'SharedWithMe'])
},
canDeleteInView() {
let routes = ['TeamFolders', 'SharedWithMe', 'RecentUploads', 'MySharedItems', 'Trash', 'Public', 'Files']
return !this.$isThisRoute(this.$route, routes) || this.clipboard.length === 0
},
canMoveInView() {
let routes = ['SharedWithMe', 'RecentUploads', 'MySharedItems', 'Public', 'Files', 'TeamFolders']
return !this.$isThisRoute(this.$route, routes) || this.clipboard.length === 0
},
canShareInView() {
let routes = ['TeamFolders', 'RecentUploads', 'MySharedItems', 'Public', 'Files']
return !this.$isThisRoute(this.$route, routes) || this.clipboard.length > 1 || this.clipboard.length === 0
},
canCreateTeamFolderInView() {
let routes = ['MySharedItems', 'Files']
return this.$isThisRoute(this.$route, routes)
&& this.clipboard.length === 1
&& this.clipboard[0].data.type === 'folder'
}
},
methods: {
toggleNavigationBars() {
this.$store.dispatch('toggleNavigationBars')
},
goBack() {
if (this.isNotHomepage) this.$router.back()
},
showTeamFolderMenu() {
if (this.teamFolder)
events.$emit('popover:open', 'team-folder')
},
showCreateMenu() {
events.$emit('popover:open', 'desktop-create')
},
showSortingMenu() {
events.$emit('popover:open', 'desktop-sorting')
},
folderActions() {
events.$emit('context-menu:current-folder', this.currentFolder)
},
},
}
return this.$isThisRoute(this.$route, routes) && this.clipboard.length === 1 && this.clipboard[0].data.type === 'folder'
},
},
methods: {
toggleNavigationBars() {
this.$store.dispatch('toggleNavigationBars')
},
goBack() {
if (this.isNotHomepage) this.$router.back()
},
showTeamFolderMenu() {
if (this.teamFolder) events.$emit('popover:open', 'team-folder')
},
showCreateMenu() {
events.$emit('popover:open', 'desktop-create')
},
showSortingMenu() {
events.$emit('popover:open', 'desktop-sorting')
},
folderActions() {
events.$emit('context-menu:current-folder', this.currentFolder)
},
},
}
</script>
<style scoped lang="scss">
@import "resources/sass/vuefilemanager/_variables";
@import "resources/sass/vuefilemanager/_mixins";
@import 'resources/sass/vuefilemanager/_variables';
@import 'resources/sass/vuefilemanager/_mixins';
.is-inactive {
opacity: 0.25;
pointer-events: none;
opacity: 0.25;
pointer-events: none;
}
.toolbar-wrapper {
padding-top: 10px;
padding-bottom: 10px;
display: flex;
justify-content: space-between;
align-items: center;
position: relative;
z-index: 2;
padding-top: 10px;
padding-bottom: 10px;
display: flex;
justify-content: space-between;
align-items: center;
position: relative;
z-index: 2;
}
.location {
align-items: center;
cursor: pointer;
display: flex;
align-items: center;
cursor: pointer;
display: flex;
.icon-back {
@include transition(150ms);
pointer-events: none;
margin-right: 6px;
shrink: 0;
}
.icon-back {
@include transition(150ms);
pointer-events: none;
margin-right: 6px;
shrink: 0;
}
.location-title {
@include font-size(15);
line-height: 1;
font-weight: 700;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
color: $text;
}
.location-title {
@include font-size(15);
line-height: 1;
font-weight: 700;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
color: $text;
}
.location-more {
margin-left: 6px;
padding: 1px 4px;
line-height: 0;
border-radius: 3px;
.location-more {
margin-left: 6px;
padding: 1px 4px;
line-height: 0;
border-radius: 3px;
svg circle {
@include transition(150ms);
}
svg circle {
@include transition(150ms);
}
&:hover {
background: $light_background;
&:hover {
background: $light_background;
svg circle {
color: inherit;
}
}
}
svg circle {
color: inherit;
}
}
}
}
.toolbar-position {
text-align: center;
text-align: center;
span {
@include font-size(17);
font-weight: 600;
}
span {
@include font-size(17);
font-weight: 600;
}
}
@media only screen and (max-width: 1024px) {
.location {
.location {
.location-title {
max-width: 120px;
}
}
.location-title {
max-width: 120px;
}
}
.toolbar-tools {
.button {
margin-left: 0;
height: 40px;
width: 40px;
}
}
.toolbar-tools {
.button {
margin-left: 0;
height: 40px;
width: 40px;
}
}
}
.dark {
.toolbar .directory-name {
color: $dark_mode_text_primary;
}
.toolbar .directory-name {
color: $dark_mode_text_primary;
}
.location {
.location-title {
color: $dark_mode_text_primary;
}
.location {
.location-title {
color: $dark_mode_text_primary;
}
.location-more {
&:hover {
background: $dark_mode_foreground;
}
}
}
.location-more {
&:hover {
background: $dark_mode_foreground;
}
}
}
}
</style>

View File

@@ -1,27 +1,19 @@
<template>
<TitlePreview
icon="check-square"
:title="title"
:subtitle="subtitle"
id="drag-ui"
v-show="isVisible"
/>
<TitlePreview icon="check-square" :title="title" :subtitle="subtitle" id="drag-ui" v-show="isVisible" />
</template>
<script>
import TitlePreview from "./TitlePreview";
import TitlePreview from './TitlePreview'
import { mapGetters } from 'vuex'
import { events } from '../../bus'
export default {
name: 'DragUI',
components: {
TitlePreview
},
TitlePreview,
},
computed: {
...mapGetters([
'clipboard'
]),
...mapGetters(['clipboard']),
title() {
let filesLength = this.clipboard.length,
hasDraggedItem = this.clipboard.includes(this.draggedItem)
@@ -46,7 +38,6 @@ export default {
}
if ((filesLength < 2 || !hasDraggedItem) && this.draggedItem) {
// Subtitle for single folder
if (this.draggedItem.data.type === 'folder') {
return this.draggedItem.items == 0 ? this.$t('folder.empty') : this.$tc('folder.item_counts', this.draggedItem.items)
@@ -57,16 +48,16 @@ export default {
return '.' + this.draggedItem.data.attributes.mimetype
}
}
}
},
},
data() {
return {
isVisible: false,
draggedItem: undefined
draggedItem: undefined,
}
},
created() {
events.$on('dragstart', data => {
events.$on('dragstart', (data) => {
this.draggedItem = data
setTimeout(() => {
@@ -74,8 +65,8 @@ export default {
}, 100)
})
events.$on('drop', () => this.isVisible = false)
}
events.$on('drop', () => (this.isVisible = false))
},
}
</script>
@@ -100,5 +91,4 @@ export default {
background: $dark_mode_foreground;
}
}
</style>

View File

@@ -1,65 +1,60 @@
<template>
<div class="flex items-center justify-center h-full" v-if="isLoading || isEmpty">
<div class="flex h-full items-center justify-center" v-if="isLoading || isEmpty">
<!--Show message for user-->
<div v-if="!isLoading" class="text-content text-center">
<slot></slot>
</div>
<!--Show message for user-->
<div v-if="!isLoading" class="text-content text-center">
<slot></slot>
</div>
<!--Show spinner when loading content-->
<div v-else class="sm:relative fixed top-0 bottom-0">
<Spinner />
</div>
<!--Show spinner when loading content-->
<div v-else class="fixed top-0 bottom-0 sm:relative">
<Spinner />
</div>
</div>
</template>
<script>
import Spinner from "./Spinner";
import {mapGetters} from 'vuex'
import Spinner from './Spinner'
import { mapGetters } from 'vuex'
export default {
name: 'EmptyFilePage',
components: {
Spinner,
},
computed: {
...mapGetters([
'isLoading',
'entries',
]),
isEmpty() {
return this.entries && this.entries.length === 0
}
}
}
export default {
name: 'EmptyFilePage',
components: {
Spinner,
},
computed: {
...mapGetters(['isLoading', 'entries']),
isEmpty() {
return this.entries && this.entries.length === 0
},
},
}
</script>
<style scoped lang="scss">
@import '../../../sass/vuefilemanager/variables';
@import '../../../sass/vuefilemanager/mixins';
@import '../../../sass/vuefilemanager/variables';
@import '../../../sass/vuefilemanager/mixins';
.title {
@include font-size(20);
color: $text;
font-weight: 700;
margin: 0;
}
.title {
@include font-size(20);
color: $text;
font-weight: 700;
margin: 0;
}
.description {
@include font-size(13);
color: $text-muted;
margin-bottom: 20px;
display: block;
}
.description {
@include font-size(13);
color: $text-muted;
margin-bottom: 20px;
display: block;
}
.dark {
.dark {
.title {
color: $dark_mode_text_primary;
}
.title {
color: $dark_mode_text_primary;
}
.description {
color: $dark_mode_text_secondary;
}
}
.description {
color: $dark_mode_text_secondary;
}
}
</style>

View File

@@ -1,12 +1,11 @@
<template>
<div class="sticky dark:bg-dark-background bg-white top-14 pb-3 px-4 z-20 whitespace-nowrap overflow-x-auto lg:hidden block">
<div class="sticky top-14 z-20 block overflow-x-auto whitespace-nowrap bg-white px-4 pb-3 dark:bg-dark-background lg:hidden">
<!--Show Buttons-->
<div v-if="! isMultiSelectMode" class="mobile-actions">
<slot></slot>
<div v-if="!isMultiSelectMode" class="mobile-actions">
<slot></slot>
</div>
<!-- Multi select mode -->
<!-- Multi select mode -->
<div v-if="isMultiSelectMode" class="mobile-actions">
<MobileActionButton @click.native="selectAll" icon="check-square">
{{ $t('mobile_selecting.select_all') }}
@@ -20,60 +19,58 @@
</div>
<!--Upload Progressbar-->
<UploadProgress class="pt-3"/>
<UploadProgress class="pt-3" />
</div>
</template>
<script>
import MobileActionButton from "./MobileActionButton";
import UploadProgress from "./UploadProgress";
import {mapGetters} from "vuex";
import MobileActionButton from './MobileActionButton'
import UploadProgress from './UploadProgress'
import { mapGetters } from 'vuex'
export default {
name: 'FileActionsMobile',
components: {
MobileActionButton,
UploadProgress,
export default {
name: 'FileActionsMobile',
components: {
MobileActionButton,
UploadProgress,
},
computed: {
...mapGetters(['isMultiSelectMode']),
},
methods: {
selectAll() {
this.$store.commit('ADD_ALL_ITEMS_TO_CLIPBOARD')
},
computed: {
...mapGetters([
'isMultiSelectMode'
])
},
methods: {
selectAll() {
this.$store.commit('ADD_ALL_ITEMS_TO_CLIPBOARD')
},
deselectAll() {
this.$store.commit('CLIPBOARD_CLEAR')
},
disableMultiSelectMode() {
this.$store.commit('TOGGLE_MULTISELECT_MODE')
},
}
}
deselectAll() {
this.$store.commit('CLIPBOARD_CLEAR')
},
disableMultiSelectMode() {
this.$store.commit('TOGGLE_MULTISELECT_MODE')
},
},
}
</script>
<style scoped lang="scss">
@import '../../../sass/vuefilemanager/variables';
@import '../../../sass/vuefilemanager/mixins';
@import '../../../sass/vuefilemanager/variables';
@import '../../../sass/vuefilemanager/mixins';
.button-enter-active,
.button-leave-active {
transition: all 250ms;
}
.button-enter-active,
.button-leave-active {
transition: all 250ms;
}
.button-enter {
opacity: 0;
transform: translateY(-50%);
}
.button-enter {
opacity: 0;
transform: translateY(-50%);
}
.button-leave-to {
opacity: 0;
transform: translateY(50%);
}
.button-leave-to {
opacity: 0;
transform: translateY(50%);
}
.button-leave-active {
position: absolute;
}
.button-leave-active {
position: absolute;
}
</style>

View File

@@ -1,158 +1,155 @@
<template>
<div
:class="{
'user-dropping-file': isDragging,
'grid-view': itemViewType === 'grid' && ! isVisibleSidebar,
'grid-view-sidebar': itemViewType === 'grid' && isVisibleSidebar
}"
class="lg:w-full lg:overflow-y-auto lg:h-full lg:px-0 px-4"
@drop.stop.prevent="uploadDroppedItems($event)"
@keydown.delete="deleteItems"
@dragover="dragEnter"
@dragleave="dragLeave"
@dragover.prevent
tabindex="-1"
@click.self="deselect"
>
<ItemHandler
@click.native="hideContextMenu"
@dragstart="dragStart(item)"
@drop.stop.native.prevent="dragFinish(item, $event)"
@contextmenu.native.prevent="contextMenu($event, item)"
:class="draggedItems.includes(item) ? 'opacity-60' : ''"
v-for="item in entries"
:key="item.data.id"
:item="item"
/>
:class="{
'user-dropping-file': isDragging,
'grid-view': itemViewType === 'grid' && !isVisibleSidebar,
'grid-view-sidebar': itemViewType === 'grid' && isVisibleSidebar,
}"
class="px-4 lg:h-full lg:w-full lg:overflow-y-auto lg:px-0"
@drop.stop.prevent="uploadDroppedItems($event)"
@keydown.delete="deleteItems"
@dragover="dragEnter"
@dragleave="dragLeave"
@dragover.prevent
tabindex="-1"
@click.self="deselect"
>
<ItemHandler
@click.native="hideContextMenu"
@dragstart="dragStart(item)"
@drop.stop.native.prevent="dragFinish(item, $event)"
@contextmenu.native.prevent="contextMenu($event, item)"
:class="draggedItems.includes(item) ? 'opacity-60' : ''"
v-for="item in entries"
:key="item.data.id"
:item="item"
/>
</div>
</template>
<script>
import ItemHandler from "./ItemHandler";
import {events} from "../../bus";
import {mapGetters} from 'vuex'
import ItemHandler from './ItemHandler'
import { events } from '../../bus'
import { mapGetters } from 'vuex'
export default {
name: 'FileBrowser',
components: {
ItemHandler,
},
computed: {
...mapGetters([
'isVisibleSidebar',
'currentFolder',
'itemViewType',
'clipboard',
'entries'
]),
draggedItems() {
// Set opacity for dragged items
if (!this.clipboard.includes(this.draggingId)) {
return [this.draggingId]
}
export default {
name: 'FileBrowser',
components: {
ItemHandler,
},
computed: {
...mapGetters(['isVisibleSidebar', 'currentFolder', 'itemViewType', 'clipboard', 'entries']),
draggedItems() {
// Set opacity for dragged items
if (!this.clipboard.includes(this.draggingId)) {
return [this.draggingId]
}
if (this.clipboard.includes(this.draggingId)) {
return this.clipboard
}
}
},
data() {
return {
draggingId: undefined,
isDragging: false,
}
},
methods: {
deleteItems() {
if (this.clipboard.length > 0 && this.$checkPermission('master') || this.$checkPermission('editor')) {
this.$store.dispatch('deleteItem')
}
},
uploadDroppedItems(event) {
this.$uploadDraggedFiles(event, this.currentFolder.data.id)
if (this.clipboard.includes(this.draggingId)) {
return this.clipboard
}
},
},
data() {
return {
draggingId: undefined,
isDragging: false,
}
},
methods: {
deleteItems() {
if ((this.clipboard.length > 0 && this.$checkPermission('master')) || this.$checkPermission('editor')) {
this.$store.dispatch('deleteItem')
}
},
uploadDroppedItems(event) {
this.$uploadDraggedFiles(event, this.currentFolder.data.id)
this.isDragging = false
},
dragEnter() {
this.isDragging = true
},
dragLeave() {
this.isDragging = false
},
dragStart(data) {
let img = document.createElement('img')
img.src = "data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7"
event.dataTransfer.setDragImage(img, 0, 0)
this.isDragging = false
},
dragEnter() {
this.isDragging = true
},
dragLeave() {
this.isDragging = false
},
dragStart(data) {
let img = document.createElement('img')
img.src = 'data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7'
event.dataTransfer.setDragImage(img, 0, 0)
events.$emit('dragstart', data)
events.$emit('dragstart', data)
// Store dragged folder
this.draggingId = data
// Store dragged folder
this.draggingId = data
// TODO: founded issue on firefox
},
dragFinish(data, event) {
// TODO: founded issue on firefox
},
dragFinish(data, event) {
if (event.dataTransfer.items.length === 0) {
// Prevent to drop on file or image
if (data.data.type !== 'folder' || this.draggingId === data) return
if (event.dataTransfer.items.length === 0) {
// Prevent to drop on file or image
if (data.data.type !== 'folder' || this.draggingId === data) return
// Prevent move selected folder to folder if in between selected folders
if (this.clipboard.find((item) => item === data && this.clipboard.length > 1)) return
// Prevent move selected folder to folder if in between selected folders
if (this.clipboard.find(item => item === data && this.clipboard.length > 1)) return
// Move item if is not included in selected items
if (!this.clipboard.includes(this.draggingId)) {
this.$store.dispatch('moveItem', {
to_item: data,
noSelectedItem: this.draggingId,
})
}
// Move item if is not included in selected items
if (!this.clipboard.includes(this.draggingId)) {
this.$store.dispatch('moveItem', {to_item: data, noSelectedItem: this.draggingId})
}
// Move selected items to folder
if (this.clipboard.length > 0 && this.clipboard.includes(this.draggingId)) {
this.$store.dispatch('moveItem', {
to_item: data,
noSelectedItem: null,
})
}
} else {
// Get id from current folder
const id = data.data.type !== 'folder' ? this.currentFolder.data.id : data.data.id
// Move selected items to folder
if (this.clipboard.length > 0 && this.clipboard.includes(this.draggingId)) {
this.$store.dispatch('moveItem', {to_item: data, noSelectedItem: null})
}
// Upload external file
this.$uploadDraggedFiles(event, id)
}
} else {
this.isDragging = false
},
contextMenu(event, item) {
events.$emit('context-menu:show', event, item)
},
hideContextMenu() {
events.$emit('context-menu:hide')
},
deselect() {
// Hide context menu
events.$emit('context-menu:hide')
// Get id from current folder
const id = data.data.type !== 'folder' ? this.currentFolder.data.id : data.data.id
// Clear clipboard
this.$store.commit('CLIPBOARD_CLEAR')
},
},
created() {
events.$on('drop', () => {
this.isDragging = false
// Upload external file
this.$uploadDraggedFiles(event, id)
}
this.isDragging = false
},
contextMenu(event, item) {
events.$emit('context-menu:show', event, item)
},
hideContextMenu() {
events.$emit('context-menu:hide')
},
deselect() {
// Hide context menu
events.$emit('context-menu:hide')
// Clear clipboard
this.$store.commit('CLIPBOARD_CLEAR')
}
},
created() {
events.$on('drop', () => {
this.isDragging = false
setTimeout(() => {
this.draggingId = undefined
}, 10)
})
}
}
setTimeout(() => {
this.draggingId = undefined
}, 10)
})
},
}
</script>
<style>
.grid-view {
@apply grid content-start xl:grid-cols-6 sm:grid-cols-4 grid-cols-3 xl:gap-4 lg:gap-2
}
.grid-view {
@apply grid grid-cols-3 content-start sm:grid-cols-4 lg:gap-2 xl:grid-cols-6 xl:gap-4;
}
.grid-view-sidebar {
@apply grid content-start 2xl:grid-cols-5 xl:grid-cols-4 lg:grid-cols-3 md:grid-cols-2 grid-cols-3 xl:gap-4 lg:gap-2
}
.grid-view-sidebar {
@apply grid grid-cols-3 content-start md:grid-cols-2 lg:grid-cols-3 lg:gap-2 xl:grid-cols-4 xl:gap-4 2xl:grid-cols-5;
}
</style>

View File

@@ -9,18 +9,24 @@
</OptionGroup>
<OptionGroup>
<Option @click.native="goToTeamFolders" :title="$t('Team Folders')" icon="users" :is-active="$isThisRoute($route, 'TeamFolders')" :is-hover-disabled="true" />
<Option @click.native="goToSharedWithMe" :title="$t('Shared with Me')" icon="user-check" :is-active="$isThisRoute($route, 'SharedWithMe')" :is-hover-disabled="true" />
<Option
@click.native="goToSharedWithMe"
:title="$t('Shared with Me')"
icon="user-check"
:is-active="$isThisRoute($route, 'SharedWithMe')"
:is-hover-disabled="true"
/>
</OptionGroup>
</MenuMobileGroup>
</MenuMobile>
</template>
<script>
import MenuMobileGroup from "../Mobile/MenuMobileGroup";
import MenuMobileGroup from '../Mobile/MenuMobileGroup'
import OptionGroup from '../FilesView/OptionGroup'
import MenuMobile from '../Mobile/MenuMobile'
import Option from '../FilesView/Option'
import {mapGetters} from 'vuex'
import { mapGetters } from 'vuex'
export default {
name: 'MobileContextMenu',
@@ -32,23 +38,23 @@ export default {
},
methods: {
goToFiles() {
this.$router.push({name: 'Files'})
this.$router.push({ name: 'Files' })
},
goToLatest() {
this.$router.push({name: 'RecentUploads'})
this.$router.push({ name: 'RecentUploads' })
},
goToShared() {
this.$router.push({name: 'MySharedItems'})
this.$router.push({ name: 'MySharedItems' })
},
goToTrash() {
this.$router.push({name: 'Trash'})
this.$router.push({ name: 'Trash' })
},
goToTeamFolders() {
this.$router.push({name: 'TeamFolders'})
this.$router.push({ name: 'TeamFolders' })
},
goToSharedWithMe() {
this.$router.push({name: 'SharedWithMe'})
this.$router.push({ name: 'SharedWithMe' })
},
}
},
}
</script>

View File

@@ -1,23 +1,22 @@
<template>
<div class="flex items-center justify-center">
<span class="text-theme dark-text-theme lg:text-xs text-tiny font-semibold absolute z-10 inline-block mx-auto mt-1 w-7 text-ellipsis overflow-hidden text-center">
{{ entry.data.attributes.mimetype }}
</span>
<div class="flex items-center justify-center">
<span class="text-theme dark-text-theme absolute z-10 mx-auto mt-1 inline-block w-7 overflow-hidden text-ellipsis text-center text-tiny font-semibold lg:text-xs">
{{ entry.data.attributes.mimetype }}
</span>
<svg width="38px" height="51px" viewBox="0 0 38 51" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<path
stroke-width="0"
fill="#f4f5f6"
d="M22.1666667,13.546875 L22.1666667,0 L2.375,0 C1.05885417,0 0,1.06582031 0,2.390625 L0,48.609375 C0,49.9341797 1.05885417,51 2.375,51 L35.625,51 C36.9411458,51 38,49.9341797 38,48.609375 L38,15.9375 L24.5416667,15.9375 C23.2354167,15.9375 22.1666667,14.8617187 22.1666667,13.546875 Z M38,12.1423828 L38,12.75 L25.3333333,12.75 L25.3333333,0 L25.9369792,0 C26.5703125,0 27.1739583,0.249023438 27.6192708,0.697265625 L37.3072917,10.4589844 C37.7526042,10.9072266 38,11.5148437 38,12.1423828 Z"></path>
</svg>
</div>
<svg width="38px" height="51px" viewBox="0 0 38 51" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<path
stroke-width="0"
fill="#f4f5f6"
d="M22.1666667,13.546875 L22.1666667,0 L2.375,0 C1.05885417,0 0,1.06582031 0,2.390625 L0,48.609375 C0,49.9341797 1.05885417,51 2.375,51 L35.625,51 C36.9411458,51 38,49.9341797 38,48.609375 L38,15.9375 L24.5416667,15.9375 C23.2354167,15.9375 22.1666667,14.8617187 22.1666667,13.546875 Z M38,12.1423828 L38,12.75 L25.3333333,12.75 L25.3333333,0 L25.9369792,0 C26.5703125,0 27.1739583,0.249023438 27.6192708,0.697265625 L37.3072917,10.4589844 C37.7526042,10.9072266 38,11.5148437 38,12.1423828 Z"
></path>
</svg>
</div>
</template>
<script>
export default {
name: 'FileIconThumbnail',
props: [
'entry'
]
name: 'FileIconThumbnail',
props: ['entry'],
}
</script>
</script>

View File

@@ -7,8 +7,8 @@
</template>
<script>
import FileSortingOptions from "./FileSortingOptions";
import MenuMobileGroup from "../Mobile/MenuMobileGroup";
import FileSortingOptions from './FileSortingOptions'
import MenuMobileGroup from '../Mobile/MenuMobileGroup'
import MenuMobile from '../Mobile/MenuMobile'
export default {

View File

@@ -12,8 +12,7 @@
</template>
<script>
import OptionGroup from "./OptionGroup";
import OptionGroup from './OptionGroup'
import Option from './Option'
import { ArrowUpIcon } from 'vue-feather-icons'
import { mapGetters } from 'vuex'
@@ -26,34 +25,30 @@ export default {
Option,
},
computed: {
...mapGetters([
'itemViewType'
]),
...mapGetters(['itemViewType']),
isGrid() {
return this.itemViewType === 'grid'
},
isList() {
return this.itemViewType === 'list'
},
arrowForCreatedAtField() {
if (this.filter.field !== 'created_at')
return undefined
arrowForCreatedAtField() {
if (this.filter.field !== 'created_at') return undefined
return this.filter.sort === 'DESC' ? 'up' : 'down'
},
arrowForNameField() {
if (this.filter.field !== 'name')
return undefined
return this.filter.sort === 'DESC' ? 'up' : 'down'
},
arrowForNameField() {
if (this.filter.field !== 'name') return undefined
return this.filter.sort === 'DESC' ? 'up' : 'down'
}
return this.filter.sort === 'DESC' ? 'up' : 'down'
},
},
data() {
return {
filter: {
sort: 'DESC',
field: undefined
}
field: undefined,
},
}
},
methods: {
@@ -61,28 +56,32 @@ export default {
this.filter.field = field
// Set sorting direction
if (this.filter.sort === 'DESC')
this.filter.sort = 'ASC'
else if (this.filter.sort === 'ASC')
this.filter.sort = 'DESC'
if (this.filter.sort === 'DESC') this.filter.sort = 'ASC'
else if (this.filter.sort === 'ASC') this.filter.sort = 'DESC'
// Save to localStorage sorting options
localStorage.setItem('sorting', JSON.stringify({ sort: this.filter.sort, field: this.filter.field }))
localStorage.setItem(
'sorting',
JSON.stringify({
sort: this.filter.sort,
field: this.filter.field,
})
)
// Update sorting state in vuex
this.$store.commit('UPDATE_SORTING')
// Get data of user with favourites tree
this.$store.dispatch('getAppData')
// Get data of user with favourites tree
this.$store.dispatch('getAppData')
// Get data of Navigator tree
this.$store.dispatch('getFolderTree')
// Get data of Navigator tree
this.$store.dispatch('getFolderTree')
this.$getDataByLocation()
this.$getDataByLocation()
},
changePreview(previewType) {
this.$store.dispatch('togglePreviewType', previewType)
}
},
},
mounted() {
let sorting = JSON.parse(localStorage.getItem('sorting'))
@@ -90,6 +89,6 @@ export default {
// Set default sorting if in not setup in LocalStorage
this.filter.sort = sorting ? sorting.sort : 'DESC'
this.filter.field = sorting ? sorting.field : 'created_at'
}
},
}
</script>

View File

@@ -1,27 +1,20 @@
<template>
<div>
<VueFolderIcon
v-if="!item.data.attributes.isTeamFolder"
/>
<VueFolderTeamIcon
v-if="item.data.attributes.isTeamFolder"
style="width: 53px; height: 52px"
/>
<VueFolderIcon v-if="!item.data.attributes.isTeamFolder" />
<VueFolderTeamIcon v-if="item.data.attributes.isTeamFolder" style="width: 53px; height: 52px" />
</div>
</template>
<script>
import VueFolderTeamIcon from "./Icons/VueFolderTeamIcon"
import VueFolderIcon from "./Icons/VueFolderIcon"
import VueFolderTeamIcon from './Icons/VueFolderTeamIcon'
import VueFolderIcon from './Icons/VueFolderIcon'
export default {
name: 'FolderIcon',
props: [
'item',
],
components: {
VueFolderTeamIcon,
VueFolderIcon,
},
}
</script>
export default {
name: 'FolderIcon',
props: ['item'],
components: {
VueFolderTeamIcon,
VueFolderIcon,
},
}
</script>

View File

@@ -1,22 +1,36 @@
<template>
<svg class="alphabet-icon" fill="none" stroke="currentColor" stroke-width="2" fill-rule="evenodd" stroke-linecap="round" stroke-linejoin="round" :width="`${size}px`" :height="`${size}px`" viewBox="-2 0 15 15" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<svg
class="alphabet-icon"
fill="none"
stroke="currentColor"
stroke-width="2"
fill-rule="evenodd"
stroke-linecap="round"
stroke-linejoin="round"
:width="`${size}px`"
:height="`${size}px`"
viewBox="-2 0 15 15"
version="1.1"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
>
<polyline id="Path" points="11.1999993 13.1999991 5.59999967 0.199999094 0 13.1999991 5.59999967 0.199999094"></polyline>
<line x1="2.25" y1="8" x2="8.75" y2="8" id="Line-2"></line>
</svg>
</svg>
</template>
<script>
export default {
props: ['size']
props: ['size'],
}
</script>
<style lang="scss">
.alphabet-icon {
polyline, line, g {
color: inherit;
}
.alphabet-icon {
polyline,
line,
g {
color: inherit;
}
</style>
}
</style>

View File

@@ -1,23 +1,39 @@
<template>
<svg class="preview-list-icon" fill="none" stroke="currentColor" stroke-width="1.5" fill-rule="evenodd" stroke-linecap="round" stroke-linejoin="round" width="15px" height="15px" viewBox="0 0 17 12" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<path d="M14.2729998,10.7729998 C15.6774712,10.0073227 16.384111,8.38688297 15.9895447,6.83668332 C15.5949785,5.28648367 14.1996249,4.20105605 12.5999998,4.19999993 L11.7179998,4.19999993 C11.1377566,1.9556703 9.23470173,0.300843012 6.93154234,0.0378706728 C4.62838295,-0.225101666 2.40127934,0.958148431 1.33005562,3.01391529 C0.258831904,5.06968215 0.564955244,7.57295196 2.09999996,9.30999984" id="Path"></path>
<line x1="8.5" y1="7" x2="8.5" y2="12" id="Path"></line>
<line x1="6" y1="9.5" x2="11" y2="9.5" id="Path"></line>
</svg>
<svg
class="preview-list-icon"
fill="none"
stroke="currentColor"
stroke-width="1.5"
fill-rule="evenodd"
stroke-linecap="round"
stroke-linejoin="round"
width="15px"
height="15px"
viewBox="0 0 17 12"
version="1.1"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
>
<path
d="M14.2729998,10.7729998 C15.6774712,10.0073227 16.384111,8.38688297 15.9895447,6.83668332 C15.5949785,5.28648367 14.1996249,4.20105605 12.5999998,4.19999993 L11.7179998,4.19999993 C11.1377566,1.9556703 9.23470173,0.300843012 6.93154234,0.0378706728 C4.62838295,-0.225101666 2.40127934,0.958148431 1.33005562,3.01391529 C0.258831904,5.06968215 0.564955244,7.57295196 2.09999996,9.30999984"
id="Path"
></path>
<line x1="8.5" y1="7" x2="8.5" y2="12" id="Path"></line>
<line x1="6" y1="9.5" x2="11" y2="9.5" id="Path"></line>
</svg>
</template>
<script>
export default {
name: "CloudPlusIcon",
};
export default {
name: 'CloudPlusIcon',
}
</script>
<style lang="scss">
.preview-list-icon {
path, line {
color: inherit;
}
.preview-list-icon {
path,
line {
color: inherit;
}
</style>
}
</style>

View File

@@ -1,25 +1,40 @@
<template>
<svg class="preview-list-icon" fill="none" stroke="currentColor" stroke-width="1.5" fill-rule="evenodd" stroke-linecap="round" stroke-linejoin="round" :width="`${size}px`" :height="`${size}px`" viewBox="0 -2 14 17" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<path d="M0,10.6420028 C0,8.60583431 0,5.5515816 0,1.47924466 C0,0.662280392 0.633305625,0 1.4145277,0 L4.95084696,0 L6.36537467,2.21886699 L12.7307493,2.21886699 C13.5119714,2.21886699 14.145277,2.88114738 14.145277,3.69811164 C14.145277,7.76603445 14.145277,7.76603445 14.145277,11.8339573 C14.145277,12.6509215 13.5119714,13.3132019 12.7307493,13.3132019 C11.9928651,13.3132019 12.1671651,13.3132019 11.798223,13.3132019" id="Path"></path>
<polyline id="Path-Copy-8" points="9.49893123 9.53496452 6.74946561 6.60112928 4 9.53496452"></polyline>
<line x1="6.74946561" y1="6.60112928" x2="6.74946561" y2="13.2022586" id="Path-Copy-7"></line>
</svg>
<svg
class="preview-list-icon"
fill="none"
stroke="currentColor"
stroke-width="1.5"
fill-rule="evenodd"
stroke-linecap="round"
stroke-linejoin="round"
:width="`${size}px`"
:height="`${size}px`"
viewBox="0 -2 14 17"
version="1.1"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
>
<path
d="M0,10.6420028 C0,8.60583431 0,5.5515816 0,1.47924466 C0,0.662280392 0.633305625,0 1.4145277,0 L4.95084696,0 L6.36537467,2.21886699 L12.7307493,2.21886699 C13.5119714,2.21886699 14.145277,2.88114738 14.145277,3.69811164 C14.145277,7.76603445 14.145277,7.76603445 14.145277,11.8339573 C14.145277,12.6509215 13.5119714,13.3132019 12.7307493,13.3132019 C11.9928651,13.3132019 12.1671651,13.3132019 11.798223,13.3132019"
id="Path"
></path>
<polyline id="Path-Copy-8" points="9.49893123 9.53496452 6.74946561 6.60112928 4 9.53496452"></polyline>
<line x1="6.74946561" y1="6.60112928" x2="6.74946561" y2="13.2022586" id="Path-Copy-7"></line>
</svg>
</template>
<script>
export default {
props: ['size']
props: ['size'],
}
</script>
<style lang="scss">
.preview-list-icon {
path,
line,
polyline {
color: inherit;
}
.preview-list-icon {
path,
line,
polyline {
color: inherit;
}
}
</style>

View File

@@ -1,25 +1,38 @@
<template>
<svg class="preview-list-icon" fill="none" stroke="currentColor" stroke-width="1.5" fill-rule="evenodd" stroke-linecap="round" stroke-linejoin="round" width="15px" height="15px" viewBox="0 0 20 16" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<rect x="9.77777778" y="0" width="6.22222222" height="6.22222222"></rect>
<rect x="9.77777778" y="9.77777778" width="6.22222222" height="6.22222222"></rect>
<line x1="0" y1="2" x2="6" y2="2"></line>
<line x1="0" y1="8" x2="6" y2="8"></line>
<line x1="0" y1="14" x2="6" y2="14"></line>
<svg
class="preview-list-icon"
fill="none"
stroke="currentColor"
stroke-width="1.5"
fill-rule="evenodd"
stroke-linecap="round"
stroke-linejoin="round"
width="15px"
height="15px"
viewBox="0 0 20 16"
version="1.1"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
>
<rect x="9.77777778" y="0" width="6.22222222" height="6.22222222"></rect>
<rect x="9.77777778" y="9.77777778" width="6.22222222" height="6.22222222"></rect>
<line x1="0" y1="2" x2="6" y2="2"></line>
<line x1="0" y1="8" x2="6" y2="8"></line>
<line x1="0" y1="14" x2="6" y2="14"></line>
</svg>
</template>
<script>
export default {
name: "SortingIcon",
};
export default {
name: 'SortingIcon',
}
</script>
<style lang="scss">
.preview-list-icon {
rect, line {
color: inherit;
}
.preview-list-icon {
rect,
line {
color: inherit;
}
</style>
}
</style>

View File

@@ -1,29 +1,29 @@
<template>
<svg width="53px" height="52px" viewBox="0 0 53 39" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<path d="M48.03125,6.5 L29.790833,6.5 C28.7431613,6.5 27.7373076,6.08896217 26.9894703,5.35523504 L22.6980297,1.14476496 C21.9501924,0.41103783 20.9443387,-6.36543387e-16 19.896667,0 L4.96875,0 L4.96875,0 C2.22455078,0 0,2.18257812 0,4.875 L0,34.125 C0,36.8174219 2.22455078,39 4.96875,39 L48.03125,39 C50.7754492,39 53,36.8174219 53,34.125 L53,11.375 C53,8.68257813 50.7754492,6.5 48.03125,6.5 Z"
class="svg-color-theme"
stroke="none"
stroke-width="0">
</path>
<path d="M48.03125,6.5 L29.790833,6.5 C28.7431613,6.5 27.7373076,6.08896217 26.9894703,5.35523504 L22.6980297,1.14476496 C21.9501924,0.41103783 20.9443387,-6.36543387e-16 19.896667,0 L4.96875,0 L4.96875,0 C2.22455078,0 0,2.18257812 0,4.875 L0,34.125 C0,36.8174219 2.22455078,39 4.96875,39 L48.03125,39 C50.7754492,39 53,36.8174219 53,34.125 L53,11.375 C53,8.68257813 50.7754492,6.5 48.03125,6.5 Z"
fill="black"
fill-opacity="0.2"
stroke="none"
stroke-width="0">
</path>
<path d="M48.03125,12.75 C49.0609313,12.75 49.9941504,13.1577174 50.6692739,13.8201027 C51.3356976,14.4739525 51.75,15.3766531 51.75,16.375 L51.75,16.375 L51.75,34.125 C51.75,35.1233469 51.3356976,36.0260475 50.6692739,36.6798973 C49.9941504,37.3422826 49.0609313,37.75 48.03125,37.75 L48.03125,37.75 L4.96875,37.75 C3.93906868,37.75 3.00584961,37.3422826 2.33072613,36.6798973 C1.66430239,36.0260475 1.25,35.1233469 1.25,34.125 L1.25,34.125 L1.25,16.375 C1.25,15.3766531 1.66430239,14.4739525 2.33072613,13.8201027 C3.00584961,13.1577174 3.93906868,12.75 4.96875,12.75 L4.96875,12.75 Z"
stroke-width="2"
class="svg-color-theme"
fill="green">
</path>
</svg>
<svg width="53px" height="52px" viewBox="0 0 53 39" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<path
d="M48.03125,6.5 L29.790833,6.5 C28.7431613,6.5 27.7373076,6.08896217 26.9894703,5.35523504 L22.6980297,1.14476496 C21.9501924,0.41103783 20.9443387,-6.36543387e-16 19.896667,0 L4.96875,0 L4.96875,0 C2.22455078,0 0,2.18257812 0,4.875 L0,34.125 C0,36.8174219 2.22455078,39 4.96875,39 L48.03125,39 C50.7754492,39 53,36.8174219 53,34.125 L53,11.375 C53,8.68257813 50.7754492,6.5 48.03125,6.5 Z"
class="svg-color-theme"
stroke="none"
stroke-width="0"
></path>
<path
d="M48.03125,6.5 L29.790833,6.5 C28.7431613,6.5 27.7373076,6.08896217 26.9894703,5.35523504 L22.6980297,1.14476496 C21.9501924,0.41103783 20.9443387,-6.36543387e-16 19.896667,0 L4.96875,0 L4.96875,0 C2.22455078,0 0,2.18257812 0,4.875 L0,34.125 C0,36.8174219 2.22455078,39 4.96875,39 L48.03125,39 C50.7754492,39 53,36.8174219 53,34.125 L53,11.375 C53,8.68257813 50.7754492,6.5 48.03125,6.5 Z"
fill="black"
fill-opacity="0.2"
stroke="none"
stroke-width="0"
></path>
<path
d="M48.03125,12.75 C49.0609313,12.75 49.9941504,13.1577174 50.6692739,13.8201027 C51.3356976,14.4739525 51.75,15.3766531 51.75,16.375 L51.75,16.375 L51.75,34.125 C51.75,35.1233469 51.3356976,36.0260475 50.6692739,36.6798973 C49.9941504,37.3422826 49.0609313,37.75 48.03125,37.75 L48.03125,37.75 L4.96875,37.75 C3.93906868,37.75 3.00584961,37.3422826 2.33072613,36.6798973 C1.66430239,36.0260475 1.25,35.1233469 1.25,34.125 L1.25,34.125 L1.25,16.375 C1.25,15.3766531 1.66430239,14.4739525 2.33072613,13.8201027 C3.00584961,13.1577174 3.93906868,12.75 4.96875,12.75 L4.96875,12.75 Z"
stroke-width="2"
class="svg-color-theme"
fill="green"
></path>
</svg>
</template>
<script>
export default {
name: 'VueFolderIcon',
}
</script>
export default {
name: 'VueFolderIcon',
}
</script>

View File

@@ -1,40 +1,52 @@
<template>
<svg viewBox="0 0 53 39" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<g id="V2" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="team-folder">
<path d="M48.03125,6.5 L29.790833,6.5 C28.7431613,6.5 27.7373076,6.08896217 26.9894703,5.35523504 L22.6980297,1.14476496 C21.9501924,0.41103783 20.9443387,-6.36543387e-16 19.896667,0 L4.96875,0 L4.96875,0 C2.22455078,0 0,2.18257812 0,4.875 L0,34.125 C0,36.8174219 2.22455078,39 4.96875,39 L48.03125,39 C50.7754492,39 53,36.8174219 53,34.125 L53,11.375 C53,8.68257813 50.7754492,6.5 48.03125,6.5 Z"
class="svg-color-theme"
stroke="none"
stroke-width="0">
</path>
<path d="M48.03125,6.5 L29.790833,6.5 C28.7431613,6.5 27.7373076,6.08896217 26.9894703,5.35523504 L22.6980297,1.14476496 C21.9501924,0.41103783 20.9443387,-6.36543387e-16 19.896667,0 L4.96875,0 L4.96875,0 C2.22455078,0 0,2.18257812 0,4.875 L0,34.125 C0,36.8174219 2.22455078,39 4.96875,39 L48.03125,39 C50.7754492,39 53,36.8174219 53,34.125 L53,11.375 C53,8.68257813 50.7754492,6.5 48.03125,6.5 Z"
fill="black"
fill-opacity="0.2"
stroke="none"
stroke-width="0">
</path>
<path d="M48.03125,12.75 C49.0609313,12.75 49.9941504,13.1577174 50.6692739,13.8201027 C51.3356976,14.4739525 51.75,15.3766531 51.75,16.375 L51.75,16.375 L51.75,34.125 C51.75,35.1233469 51.3356976,36.0260475 50.6692739,36.6798973 C49.9941504,37.3422826 49.0609313,37.75 48.03125,37.75 L48.03125,37.75 L4.96875,37.75 C3.93906868,37.75 3.00584961,37.3422826 2.33072613,36.6798973 C1.66430239,36.0260475 1.25,35.1233469 1.25,34.125 L1.25,34.125 L1.25,16.375 C1.25,15.3766531 1.66430239,14.4739525 2.33072613,13.8201027 C3.00584961,13.1577174 3.93906868,12.75 4.96875,12.75 L4.96875,12.75 Z"
stroke-width="2"
class="svg-color-theme"
fill="green">
</path>
<g id="Icon" transform="translate(8.000000, 20.000000)" class="svg-stroke-theme-darken" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.3" stroke="black" stroke-opacity="0.25">
<path d="M9.59999943,10.7999994 L9.59999943,9.59999943 C9.59999943,8.27451611 8.52548289,7.19999957 7.19999957,7.19999957 L2.39999986,7.19999957 C1.07451654,7.19999957 0,8.27451611 0,9.59999943 L0,10.7999994"></path>
<circle cx="4.79999971" cy="2.39999986" r="2.39999986"></circle>
<path d="M13.1999992,10.7999994 L13.1999992,9.59999943 C13.1991834,8.50627014 12.4589985,7.55143166 11.3999993,7.27799957"></path>
<path d="M8.99999946,0.0779999954 C10.0619483,0.349901852 10.8047053,1.30679461 10.8047053,2.40299986 C10.8047053,3.4992051 10.0619483,4.45609786 8.99999946,4.72799972"></path>
</g>
</g>
</g>
</svg>
<svg viewBox="0 0 53 39" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<g id="V2" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="team-folder">
<path
d="M48.03125,6.5 L29.790833,6.5 C28.7431613,6.5 27.7373076,6.08896217 26.9894703,5.35523504 L22.6980297,1.14476496 C21.9501924,0.41103783 20.9443387,-6.36543387e-16 19.896667,0 L4.96875,0 L4.96875,0 C2.22455078,0 0,2.18257812 0,4.875 L0,34.125 C0,36.8174219 2.22455078,39 4.96875,39 L48.03125,39 C50.7754492,39 53,36.8174219 53,34.125 L53,11.375 C53,8.68257813 50.7754492,6.5 48.03125,6.5 Z"
class="svg-color-theme"
stroke="none"
stroke-width="0"
></path>
<path
d="M48.03125,6.5 L29.790833,6.5 C28.7431613,6.5 27.7373076,6.08896217 26.9894703,5.35523504 L22.6980297,1.14476496 C21.9501924,0.41103783 20.9443387,-6.36543387e-16 19.896667,0 L4.96875,0 L4.96875,0 C2.22455078,0 0,2.18257812 0,4.875 L0,34.125 C0,36.8174219 2.22455078,39 4.96875,39 L48.03125,39 C50.7754492,39 53,36.8174219 53,34.125 L53,11.375 C53,8.68257813 50.7754492,6.5 48.03125,6.5 Z"
fill="black"
fill-opacity="0.2"
stroke="none"
stroke-width="0"
></path>
<path
d="M48.03125,12.75 C49.0609313,12.75 49.9941504,13.1577174 50.6692739,13.8201027 C51.3356976,14.4739525 51.75,15.3766531 51.75,16.375 L51.75,16.375 L51.75,34.125 C51.75,35.1233469 51.3356976,36.0260475 50.6692739,36.6798973 C49.9941504,37.3422826 49.0609313,37.75 48.03125,37.75 L48.03125,37.75 L4.96875,37.75 C3.93906868,37.75 3.00584961,37.3422826 2.33072613,36.6798973 C1.66430239,36.0260475 1.25,35.1233469 1.25,34.125 L1.25,34.125 L1.25,16.375 C1.25,15.3766531 1.66430239,14.4739525 2.33072613,13.8201027 C3.00584961,13.1577174 3.93906868,12.75 4.96875,12.75 L4.96875,12.75 Z"
stroke-width="2"
class="svg-color-theme"
fill="green"
></path>
<g
id="Icon"
transform="translate(8.000000, 20.000000)"
class="svg-stroke-theme-darken"
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="1.3"
stroke="black"
stroke-opacity="0.25"
>
<path
d="M9.59999943,10.7999994 L9.59999943,9.59999943 C9.59999943,8.27451611 8.52548289,7.19999957 7.19999957,7.19999957 L2.39999986,7.19999957 C1.07451654,7.19999957 0,8.27451611 0,9.59999943 L0,10.7999994"
></path>
<circle cx="4.79999971" cy="2.39999986" r="2.39999986"></circle>
<path d="M13.1999992,10.7999994 L13.1999992,9.59999943 C13.1991834,8.50627014 12.4589985,7.55143166 11.3999993,7.27799957"></path>
<path
d="M8.99999946,0.0779999954 C10.0619483,0.349901852 10.8047053,1.30679461 10.8047053,2.40299986 C10.8047053,3.4992051 10.0619483,4.45609786 8.99999946,4.72799972"
></path>
</g>
</g>
</g>
</svg>
</template>
<script>
export default {
name: 'VueFolderTeamIcon',
}
</script>
export default {
name: 'VueFolderTeamIcon',
}
</script>

View File

@@ -26,7 +26,7 @@
<b>{{ clipboard.metadata.ColorSpace }}</b>
</li>
<!--TODO: Colour profile:sRGB IEC61966-2.1-->
<!--TODO: Colour profile:sRGB IEC61966-2.1-->
<li v-if="clipboard.metadata.Make">
<span>{{ $t('file_detail_meta.make') }}</span>
@@ -68,42 +68,41 @@
<b>{{ clipboard.metadata.COMPUTED.CCDWidth }}</b>
</li>
<li v-if="clipboard.metadata.GPSLongitude">
<li v-if="clipboard.metadata.GPSLongitude">
<span>{{ $t('file_detail_meta.longitude') }}</span>
<b>{{ formatGps(clipboard.metadata.GPSLongitude, clipboard.metadata.GPSLongitudeRef) }}</b>
</li>
<li v-if="clipboard.metadata.GPSLatitude">
<span>{{ $t('file_detail_meta.latitude') }}</span>
<b>{{ formatGps(clipboard.metadata.GPSLatitude, clipboard.metadata.GPSLatitudeRef) }}</b>
</li>
<li v-if="clipboard.metadata.GPSLatitude">
<span>{{ $t('file_detail_meta.latitude') }}</span>
<b>{{ formatGps(clipboard.metadata.GPSLatitude, clipboard.metadata.GPSLatitudeRef) }}</b>
</li>
</ul>
</div>
</template>
<script>
import {mapGetters} from 'vuex'
import {split} from 'lodash'
import { mapGetters } from 'vuex'
import { split } from 'lodash'
export default {
name: 'ImageMetaData',
computed: {
clipboard() {
return this.$store.getters.clipboard[0].data.relationships
},
},
methods: {
formatGps(location, ref) {
let data = []
name: 'ImageMetaData',
computed: {
clipboard() {
return this.$store.getters.clipboard[0].data.relationships
},
},
methods: {
formatGps(location, ref) {
let data = []
location.forEach(location => {
data.push(split(location, '/', 2)[0])
})
return `${data[0]}° ${data[1]}' ${data[2].substr(0, 4) / 100}" ${ref} `
}
},
location.forEach((location) => {
data.push(split(location, '/', 2)[0])
})
return `${data[0]}° ${data[1]}' ${data[2].substr(0, 4) / 100}" ${ref} `
},
},
}
</script>
@@ -112,33 +111,34 @@ export default {
@import '../../../sass/vuefilemanager/mixins';
.meta-data-list {
list-style: none;
padding: 0px;
margin: 0px;
list-style: none;
padding: 0px;
margin: 0px;
li {
display: flex;
justify-content: space-between;
padding: 9px 0;
border-bottom: 1px solid $light_mode_border;
li {
display: flex;
justify-content: space-between;
padding: 9px 0;
border-bottom: 1px solid $light_mode_border;
b, span {
@include font-size(14);
color: $text;
}
}
b,
span {
@include font-size(14);
color: $text;
}
}
}
.dark {
.meta-data-list {
li {
border-color: $dark_mode_border_color;
.meta-data-list {
li {
border-color: $dark_mode_border_color;
b, span {
color: $dark_mode_text_primary !important;
}
}
}
b,
span {
color: $dark_mode_text_primary !important;
}
}
}
}
</style>
</style>

View File

@@ -1,108 +1,81 @@
<template>
<div class="2xl:w-104 w-96 px-2.5 overflow-y-auto overflow-x-hidden h-screen lg:block hidden">
<!--Is empty clipboard-->
<div v-if="isEmpty" class="flex items-center justify-center h-full">
<div class="text-center">
<eye-off-icon size="28" class="vue-feather text-gray-400 inline-block mb-3" />
<small class="text-sm block text-gray-400">
{{ $t('messages.nothing_to_preview') }}
</small>
</div>
</div>
<div class="hidden h-screen w-96 overflow-y-auto overflow-x-hidden px-2.5 lg:block 2xl:w-104">
<!--Is empty clipboard-->
<div v-if="isEmpty" class="flex h-full items-center justify-center">
<div class="text-center">
<eye-off-icon size="28" class="vue-feather mb-3 inline-block text-gray-400" />
<small class="block text-sm text-gray-400">
{{ $t('messages.nothing_to_preview') }}
</small>
</div>
</div>
<!--Multiple item selection-->
<TitlePreview
v-if="! isSingleFile && !isEmpty"
class="mb-6"
icon="check-square"
:title="$t('file_detail.selected_multiple')"
:subtitle="this.clipboard.length + ' ' + $tc('file_detail.items', this.clipboard.length)"
/>
<!--Multiple item selection-->
<TitlePreview
v-if="!isSingleFile && !isEmpty"
class="mb-6"
icon="check-square"
:title="$t('file_detail.selected_multiple')"
:subtitle="this.clipboard.length + ' ' + $tc('file_detail.items', this.clipboard.length)"
/>
<!--Single file preview-->
<!--Single file preview-->
<div v-if="isSingleFile && !isEmpty">
<FilePreviewDetail />
<TitlePreview
class="mb-6"
:icon="clipboard[0].data.type"
:title="clipboard[0].data.attributes.name"
:subtitle="clipboard[0].data.attributes.mimetype"
/>
<TitlePreview class="mb-6" :icon="clipboard[0].data.type" :title="clipboard[0].data.attributes.name" :subtitle="clipboard[0].data.attributes.mimetype" />
<!--Filesize-->
<ListInfoItem
v-if="singleFile.data.attributes.filesize"
:title="$t('file_detail.size')"
:content="singleFile.data.attributes.filesize"
/>
<!--Filesize-->
<ListInfoItem v-if="singleFile.data.attributes.filesize" :title="$t('file_detail.size')" :content="singleFile.data.attributes.filesize" />
<!--Created At-->
<ListInfoItem
:title="$t('file_detail.created_at')"
:content="singleFile.data.attributes.created_at"
/>
<!--Created At-->
<ListInfoItem :title="$t('file_detail.created_at')" :content="singleFile.data.attributes.created_at" />
<!--Location-->
<ListInfoItem
v-if="$checkPermission(['master'])"
:title="$t('file_detail.where')"
>
<div @click="$moveFileOrFolder(singleFile)" class="flex items-center cursor-pointer">
<span class="inline-block font-bold text-sm">
{{ singleFile.data.relationships.parent ? singleFile.data.relationships.parent.data.attributes.name : $t('locations.home') }}
</span>
<!--Location-->
<ListInfoItem v-if="$checkPermission(['master'])" :title="$t('file_detail.where')">
<div @click="$moveFileOrFolder(singleFile)" class="flex cursor-pointer items-center">
<span class="inline-block text-sm font-bold">
{{ singleFile.data.relationships.parent ? singleFile.data.relationships.parent.data.attributes.name : $t('locations.home') }}
</span>
<Edit2Icon size="10" class="ml-2" />
</div>
</ListInfoItem>
<!--Team-->
<ListInfoItem
v-if="singleFile.data.attributes.isTeamFolder"
:title="$t('Shared with the Team')"
>
<div class="flex items-center cursor-pointer" @click="$updateTeamFolder(singleFile)">
<!--Team-->
<ListInfoItem v-if="singleFile.data.attributes.isTeamFolder" :title="$t('Shared with the Team')">
<div class="flex cursor-pointer items-center" @click="$updateTeamFolder(singleFile)">
<TeamMembersPreview :folder="singleFile" :avatar-size="32" />
<Edit2Icon size="10" class="ml-2" />
</div>
</ListInfoItem>
<!--Shared-->
<ListInfoItem
v-if="$checkPermission('master') && singleFile.data.relationships.shared"
:title="$t('file_detail.shared')"
>
<div @click="$shareFileOrFolder(singleFile)" class="flex items-center cursor-pointer mb-2">
<span class="inline-block font-bold text-sm">
{{ sharedInfo }}
</span>
<!--Shared-->
<ListInfoItem v-if="$checkPermission('master') && singleFile.data.relationships.shared" :title="$t('file_detail.shared')">
<div @click="$shareFileOrFolder(singleFile)" class="mb-2 flex cursor-pointer items-center">
<span class="inline-block text-sm font-bold">
{{ sharedInfo }}
</span>
<Edit2Icon size="10" class="ml-2" />
</div>
<div class="flex items-center w-full">
<lock-icon v-if="isLocked" @click="$shareFileOrFolder(singleFile)" size="17" class="hover-text-theme vue-feather cursor-pointer"/>
<unlock-icon v-if="! isLocked" @click="$shareFileOrFolder(singleFile)" size="17" class="hover-text-theme vue-feather cursor-pointer"/>
<CopyShareLink :item="singleFile" size="small" class="w-full pl-2.5"/>
<div class="flex w-full items-center">
<lock-icon v-if="isLocked" @click="$shareFileOrFolder(singleFile)" size="17" class="hover-text-theme vue-feather cursor-pointer" />
<unlock-icon v-if="!isLocked" @click="$shareFileOrFolder(singleFile)" size="17" class="hover-text-theme vue-feather cursor-pointer" />
<CopyShareLink :item="singleFile" size="small" class="w-full pl-2.5" />
</div>
</ListInfoItem>
<!--Author-->
<ListInfoItem
v-if="canShowAuthor"
:title="$t('Author')"
>
<div class="flex items-center mt-1.5">
<MemberAvatar :size="32" :member="singleFile.data.relationships.owner" />
<span class="ml-3 block font-bold font-sm">
{{ singleFile.data.relationships.owner.data.attributes.name }}
</span>
<!--Author-->
<ListInfoItem v-if="canShowAuthor" :title="$t('Author')">
<div class="mt-1.5 flex items-center">
<MemberAvatar :size="32" :member="singleFile.data.relationships.owner" />
<span class="font-sm ml-3 block font-bold">
{{ singleFile.data.relationships.owner.data.attributes.name }}
</span>
</div>
</ListInfoItem>
<!--Metadata-->
<ListInfoItem
v-if="canShowMetaData"
:title="$t('file_detail_meta.meta_data')"
>
<!--Metadata-->
<ListInfoItem v-if="canShowMetaData" :title="$t('file_detail_meta.meta_data')">
<ImageMetaData />
</ListInfoItem>
</div>
@@ -110,64 +83,62 @@
</template>
<script>
import FilePreviewDetail from "../Others/FilePreviewDetail";
import CopyShareLink from "../Others/Forms/CopyShareLink";
import {Edit2Icon, LockIcon, UnlockIcon, EyeOffIcon} from 'vue-feather-icons'
import ImageMetaData from "./ImageMetaData";
import TitlePreview from "./TitlePreview";
import TeamMembersPreview from "../Teams/Components/TeamMembersPreview"
import ListInfoItem from "../Others/ListInfoItem";
import MemberAvatar from "./MemberAvatar"
import {mapGetters} from 'vuex'
import FilePreviewDetail from '../Others/FilePreviewDetail'
import CopyShareLink from '../Others/Forms/CopyShareLink'
import { Edit2Icon, LockIcon, UnlockIcon, EyeOffIcon } from 'vue-feather-icons'
import ImageMetaData from './ImageMetaData'
import TitlePreview from './TitlePreview'
import TeamMembersPreview from '../Teams/Components/TeamMembersPreview'
import ListInfoItem from '../Others/ListInfoItem'
import MemberAvatar from './MemberAvatar'
import { mapGetters } from 'vuex'
export default {
name: 'InfoSidebar',
components: {
TeamMembersPreview,
FilePreviewDetail,
ImageMetaData,
CopyShareLink,
MemberAvatar,
TitlePreview,
ListInfoItem,
UnlockIcon,
EyeOffIcon,
Edit2Icon,
LockIcon,
},
computed: {
...mapGetters([
'permissionOptions',
'clipboard',
'user',
]),
isEmpty() {
return this.clipboard.length === 0
},
isSingleFile() {
return this.clipboard.length === 1
},
singleFile() {
return this.clipboard[0]
},
canShowMetaData() {
return this.clipboard[0].data.attributes.metadata && this.clipboard[0].data.attributes.metadata.ExifImageWidth
},
isLocked() {
return this.clipboard[0].data.relationships.shared.protected
},
sharedInfo() {
let title = this.permissionOptions.find(option => {
return option.value === this.clipboard[0].data.relationships.shared.permission
})
export default {
name: 'InfoSidebar',
components: {
TeamMembersPreview,
FilePreviewDetail,
ImageMetaData,
CopyShareLink,
MemberAvatar,
TitlePreview,
ListInfoItem,
UnlockIcon,
EyeOffIcon,
Edit2Icon,
LockIcon,
},
computed: {
...mapGetters(['permissionOptions', 'clipboard', 'user']),
isEmpty() {
return this.clipboard.length === 0
},
isSingleFile() {
return this.clipboard.length === 1
},
singleFile() {
return this.clipboard[0]
},
canShowMetaData() {
return this.clipboard[0].data.attributes.metadata && this.clipboard[0].data.attributes.metadata.ExifImageWidth
},
isLocked() {
return this.clipboard[0].data.relationships.shared.protected
},
sharedInfo() {
let title = this.permissionOptions.find((option) => {
return option.value === this.clipboard[0].data.relationships.shared.permission
})
return title ? this.$t(title.label) : this.$t('shared.can_download')
},
canShowAuthor() {
return this.$isThisRoute(this.$route, ['SharedWithMe', 'TeamFolders'])
&& this.clipboard[0].data.type !== 'folder'
&& this.user.data.id !== this.clipboard[0].data.relationships.owner.data.id
},
},
}
return title ? this.$t(title.label) : this.$t('shared.can_download')
},
canShowAuthor() {
return (
this.$isThisRoute(this.$route, ['SharedWithMe', 'TeamFolders']) &&
this.clipboard[0].data.type !== 'folder' &&
this.user.data.id !== this.clipboard[0].data.relationships.owner.data.id
)
},
},
}
</script>

View File

@@ -1,221 +1,209 @@
<template>
<div
:class="{'dark:bg-dark-foreground bg-light-background': isClicked}"
class="flex flex-wrap items-center justify-center relative z-0 text-center lg:h-60 sm:h-56 h-48 px-1 pt-2 rounded-lg select-none border-2 border-transparent border-dashed dark:hover:bg-dark-foreground lg:hover:bg-light-background"
:draggable="canDrag"
spellcheck="false"
>
<div
:class="{ 'bg-light-background dark:bg-dark-foreground': isClicked }"
class="relative z-0 flex h-48 select-none flex-wrap items-center justify-center rounded-lg border-2 border-dashed border-transparent px-1 pt-2 text-center dark:hover:bg-dark-foreground sm:h-56 lg:h-60 lg:hover:bg-light-background"
:draggable="canDrag"
spellcheck="false"
>
<!--MultiSelecting for the mobile version-->
<CheckBox v-if="isMultiSelectMode" :is-clicked="isClicked" class="mr-5" />
<!--MultiSelecting for the mobile version-->
<CheckBox v-if="isMultiSelectMode" :is-clicked="isClicked" class="mr-5"/>
<div class="w-full">
<!--Item thumbnail-->
<div class="relative mx-auto">
<!--Emoji Icon-->
<Emoji v-if="entry.data.attributes.emoji" :emoji="entry.data.attributes.emoji" class="mb-10 inline-block scale-150 transform text-5xl" />
<div class="w-full">
<!--Item thumbnail-->
<div class="relative mx-auto">
<!--Folder Icon-->
<FolderIcon v-if="isFolder && !entry.data.attributes.emoji" :item="entry" class="mt-3 mb-5 inline-block scale-150 transform lg:mt-2 lg:mb-8" />
<!--Emoji Icon-->
<Emoji
v-if="entry.data.attributes.emoji"
:emoji="entry.data.attributes.emoji"
class="text-5xl transform scale-150 inline-block mb-10"
/>
<!--File Icon-->
<div v-if="isFile || isVideo || isAudio || (isImage && !entry.data.attributes.thumbnail)" class="relative mx-auto w-24">
<!--Member thumbnail for team folders-->
<MemberAvatar
v-if="user && canShowAuthor"
:size="38"
:is-border="true"
:member="entry.data.relationships.owner"
class="absolute right-2 -bottom-5 z-10 z-10 scale-75 transform lg:-bottom-7 lg:scale-100"
/>
<!--Folder Icon-->
<FolderIcon v-if="isFolder && !entry.data.attributes.emoji" :item="entry" class="inline-block transform scale-150 lg:mt-2 lg:mb-8 mt-3 mb-5" />
<FileIconThumbnail :entry="entry" class="z-0 mt-5 mb-10 scale-125 transform lg:mb-12 lg:mt-6 lg:scale-150" />
</div>
<!--File Icon-->
<div v-if="isFile || isVideo || isAudio || (isImage && !entry.data.attributes.thumbnail)" class="relative w-24 mx-auto">
<!--Image thumbnail-->
<div v-if="isImage && entry.data.attributes.thumbnail" class="relative mb-4 inline-block h-24 w-28 lg:h-28 lg:w-36">
<!--Member thumbnail for team folders-->
<MemberAvatar
v-if="user && canShowAuthor"
:size="38"
:is-border="true"
:member="entry.data.relationships.owner"
class="absolute -right-3 -bottom-2.5 z-10 scale-75 transform lg:scale-100"
/>
<!--Member thumbnail for team folders-->
<MemberAvatar
v-if="user && canShowAuthor"
:size="38"
:is-border="true"
:member="entry.data.relationships.owner"
class="absolute lg:-bottom-7 right-2 -bottom-5 z-10 transform lg:scale-100 scale-75 z-10"
/>
<img class="h-full w-full rounded-lg object-cover shadow-lg" :src="entry.data.attributes.thumbnail.sm" :alt="entry.data.attributes.name" loading="lazy" />
</div>
</div>
<FileIconThumbnail :entry="entry" class="transform lg:scale-150 scale-125 lg:mb-12 lg:mt-6 mt-5 mb-10 z-0" />
</div>
<!--Item Info-->
<div class="text-center">
<!--Item Title-->
<b
class="tracking-tigh inline-block w-full overflow-hidden text-ellipsis whitespace-nowrap text-sm leading-3 hover:underline md:px-6"
ref="name"
@input="renameItem"
@keydown.delete.stop
@click.stop
:contenteditable="canEditName"
>
{{ itemName }}
</b>
<!--Image thumbnail-->
<div v-if="isImage && entry.data.attributes.thumbnail" class="relative inline-block lg:w-36 lg:h-28 w-28 h-24 mb-4">
<!--Item sub line-->
<div class="flex items-center justify-center">
<!--Shared Icon-->
<div v-if="$checkPermission('master') && entry.data.relationships.shared">
<link-icon size="12" class="text-theme dark-text-theme vue-feather mr-1.5" />
</div>
<!--Member thumbnail for team folders-->
<MemberAvatar
v-if="user && canShowAuthor"
:size="38"
:is-border="true"
:member="entry.data.relationships.owner"
class="absolute -right-3 -bottom-2.5 transform lg:scale-100 scale-75 z-10"
/>
<!--File & Image sub line-->
<small v-if="!isFolder" class="block text-xs text-gray-500">
{{ entry.data.attributes.filesize }}<span class="hidden text-xs text-gray-500 lg:inline-block">, {{ timeStamp }}</span>
</small>
<img class="object-cover w-full h-full rounded-lg shadow-lg" :src="entry.data.attributes.thumbnail.sm" :alt="entry.data.attributes.name" loading="lazy" />
</div>
</div>
<!--Folder sub line-->
<small v-if="isFolder" class="block text-xs text-gray-500">
{{ folderItems === 0 ? $t('folder.empty') : $tc('folder.item_counts', folderItems)
}}<span class="hidden text-xs text-gray-500 lg:inline-block">, {{ timeStamp }}</span>
</small>
</div>
</div>
<!--Item Info-->
<div class="text-center">
<!-- Mobile item action button-->
<div v-if="mobileHandler && !isMultiSelectMode && $isMobile()" class="relative flex items-center justify-center py-0.5 px-2">
<div @mouseup.stop="$openInDetailPanel(entry)" class="hidden p-2.5 sm:block">
<eye-icon size="18" class="vue-feather inline-block opacity-30" />
</div>
<!--Item Title-->
<b class="inline-block leading-3 text-sm hover:underline w-full text-ellipsis overflow-hidden whitespace-nowrap md:px-6 tracking-tigh" ref="name" @input="renameItem" @keydown.delete.stop @click.stop :contenteditable="canEditName">
{{ itemName }}
</b>
<!--Item sub line-->
<div class="flex items-center justify-center">
<!--Shared Icon-->
<div v-if="$checkPermission('master') && entry.data.relationships.shared">
<link-icon size="12" class="mr-1.5 text-theme dark-text-theme vue-feather"/>
</div>
<!--File & Image sub line-->
<small v-if="! isFolder" class="block text-xs text-gray-500">
{{ entry.data.attributes.filesize }}<span class="lg:inline-block hidden text-xs text-gray-500">, {{ timeStamp }}</span>
</small>
<!--Folder sub line-->
<small v-if="isFolder" class="block text-xs text-gray-500">
{{ folderItems === 0 ? $t('folder.empty') : $tc('folder.item_counts', folderItems) }}<span class="lg:inline-block hidden text-xs text-gray-500">, {{ timeStamp }}</span>
</small>
</div>
</div>
<!-- Mobile item action button-->
<div v-if="mobileHandler && ! isMultiSelectMode && $isMobile()" class="flex items-center justify-center py-0.5 px-2 relative">
<div @mouseup.stop="$openInDetailPanel(entry)" class="p-2.5 sm:block hidden">
<eye-icon size="18" class="vue-feather opacity-30 inline-block" />
</div>
<div @mouseup.stop="showItemActions" class="p-2.5">
<MoreHorizontalIcon size="18" class="vue-feather text-theme dark-text-theme inline-block" />
</div>
</div>
</div>
</div>
<div @mouseup.stop="showItemActions" class="p-2.5">
<MoreHorizontalIcon size="18" class="vue-feather text-theme dark-text-theme inline-block" />
</div>
</div>
</div>
</div>
</template>
<script>
import FolderIcon from "./FolderIcon";
import {LinkIcon, MoreHorizontalIcon, EyeIcon} from 'vue-feather-icons'
import FileIconThumbnail from "./FileIconThumbnail"
import MemberAvatar from "./MemberAvatar"
import Emoji from "../Others/Emoji"
import CheckBox from "./CheckBox"
import {debounce} from "lodash"
import {mapGetters} from "vuex"
import {events} from "../../bus"
import FolderIcon from './FolderIcon'
import { LinkIcon, MoreHorizontalIcon, EyeIcon } from 'vue-feather-icons'
import FileIconThumbnail from './FileIconThumbnail'
import MemberAvatar from './MemberAvatar'
import Emoji from '../Others/Emoji'
import CheckBox from './CheckBox'
import { debounce } from 'lodash'
import { mapGetters } from 'vuex'
import { events } from '../../bus'
export default {
name: 'ItemList',
components: {
FileIconThumbnail,
MoreHorizontalIcon,
MemberAvatar,
FolderIcon,
CheckBox,
LinkIcon,
EyeIcon,
Emoji,
},
props: [
'mobileHandler',
'entry',
],
data() {
return {
mobileMultiSelect: false,
itemName: undefined,
}
},
computed: {
...mapGetters([
'isMultiSelectMode',
'clipboard',
'user',
]),
isClicked() {
return this.clipboard.some(element => element.data.id === this.entry.data.id)
},
isAudio() {
return this.entry.data.type === 'audio'
},
isVideo() {
return this.entry.data.type === 'video'
},
isFile() {
return this.entry.data.type === 'file'
},
isImage() {
return this.entry.data.type === 'image'
},
isFolder() {
return this.entry.data.type === 'folder'
},
timeStamp() {
return this.entry.data.attributes.deleted_at
? this.$t('entry_thumbnail.deleted_at', {time: this.entry.data.attributes.deleted_at})
: this.entry.data.attributes.created_at
},
canEditName() {
return !this.$isMobile()
&& !this.$isThisRoute(this.$route, ['Trash'])
&& !this.$checkPermission('visitor')
&& !(this.sharedDetail && this.sharedDetail.attributes.type === 'file')
},
folderItems() {
return this.entry.data.attributes.deleted_at
? this.entry.data.attributes.trashed_items
: this.entry.data.attributes.items
},
canShowAuthor() {
return this.$isThisRoute(this.$route, ['SharedWithMe', 'TeamFolders'])
&& !this.isFolder
&& this.user.data.id !== this.entry.data.relationships.owner.data.id
},
canDrag() {
return !this.isDeleted && this.$checkPermission(['master', 'editor'])
},
},
methods: {
showItemActions() {
this.$store.commit('CLIPBOARD_CLEAR')
this.$store.commit('ADD_ITEM_TO_CLIPBOARD', this.entry)
export default {
name: 'ItemList',
components: {
FileIconThumbnail,
MoreHorizontalIcon,
MemberAvatar,
FolderIcon,
CheckBox,
LinkIcon,
EyeIcon,
Emoji,
},
props: ['mobileHandler', 'entry'],
data() {
return {
mobileMultiSelect: false,
itemName: undefined,
}
},
computed: {
...mapGetters(['isMultiSelectMode', 'clipboard', 'user']),
isClicked() {
return this.clipboard.some((element) => element.data.id === this.entry.data.id)
},
isAudio() {
return this.entry.data.type === 'audio'
},
isVideo() {
return this.entry.data.type === 'video'
},
isFile() {
return this.entry.data.type === 'file'
},
isImage() {
return this.entry.data.type === 'image'
},
isFolder() {
return this.entry.data.type === 'folder'
},
timeStamp() {
return this.entry.data.attributes.deleted_at
? this.$t('entry_thumbnail.deleted_at', {
time: this.entry.data.attributes.deleted_at,
})
: this.entry.data.attributes.created_at
},
canEditName() {
return (
!this.$isMobile() &&
!this.$isThisRoute(this.$route, ['Trash']) &&
!this.$checkPermission('visitor') &&
!(this.sharedDetail && this.sharedDetail.attributes.type === 'file')
)
},
folderItems() {
return this.entry.data.attributes.deleted_at ? this.entry.data.attributes.trashed_items : this.entry.data.attributes.items
},
canShowAuthor() {
return this.$isThisRoute(this.$route, ['SharedWithMe', 'TeamFolders']) && !this.isFolder && this.user.data.id !== this.entry.data.relationships.owner.data.id
},
canDrag() {
return !this.isDeleted && this.$checkPermission(['master', 'editor'])
},
},
methods: {
showItemActions() {
this.$store.commit('CLIPBOARD_CLEAR')
this.$store.commit('ADD_ITEM_TO_CLIPBOARD', this.entry)
this.$showMobileMenu('file-menu')
events.$emit('mobile-context-menu:show', this.entry)
},
renameItem: debounce(function (e) {
this.$showMobileMenu('file-menu')
events.$emit('mobile-context-menu:show', this.entry)
},
renameItem: debounce(function (e) {
// Prevent submit empty string
if (e.target.innerText.trim() === '') return
// Prevent submit empty string
if (e.target.innerText.trim() === '') return
this.$store.dispatch('renameItem', {
id: this.entry.data.id,
type: this.entry.data.type,
name: e.target.innerText,
})
}, 300),
},
created() {
// Set item name to own component variable
this.itemName = this.entry.data.attributes.name
this.$store.dispatch('renameItem', {
id: this.entry.data.id,
type: this.entry.data.type,
name: e.target.innerText
})
}, 300)
},
created() {
// Change item name
events.$on('change:name', (item) => {
if (this.entry.data.id === item.id) this.itemName = item.name
})
// Set item name to own component variable
this.itemName = this.entry.data.attributes.name
// Change item name
events.$on('change:name', item => {
if (this.entry.data.id === item.id) this.itemName = item.name
})
// Autofocus after newly created folder
events.$on('newFolder:focus', id => {
if ( !this.$isMobile() && this.entry.data.id === id) {
this.$refs.name.focus()
document.execCommand('selectAll')
}
})
}
}
// Autofocus after newly created folder
events.$on('newFolder:focus', (id) => {
if (!this.$isMobile() && this.entry.data.id === id) {
this.$refs.name.focus()
document.execCommand('selectAll')
}
})
},
}
</script>

View File

@@ -1,57 +1,48 @@
<template>
<div>
<ItemList
v-if="itemViewType === 'list'"
:entry="item"
:highlight="true"
:mobile-handler="true"
@mouseup.stop.native="clickFilter"
@dragstart.native="$emit('dragstart')"
@drop.native="drop()"
@dragleave.native="dragLeave"
@dragover.prevent.native="dragEnter"
:class="{'border-theme': area }"
/>
<div>
<ItemList
v-if="itemViewType === 'list'"
:entry="item"
:highlight="true"
:mobile-handler="true"
@mouseup.stop.native="clickFilter"
@dragstart.native="$emit('dragstart')"
@drop.native="drop()"
@dragleave.native="dragLeave"
@dragover.prevent.native="dragEnter"
:class="{ 'border-theme': area }"
/>
<ItemGrid
v-if="itemViewType === 'grid'"
:entry="item"
:highlight="true"
:mobile-handler="true"
@mouseup.stop.native="clickFilter"
@dragstart.native="$emit('dragstart')"
@drop.native="drop()"
@dragleave.native="dragLeave"
@dragover.prevent.native="dragEnter"
:class="{'border-theme': area }"
/>
</div>
<ItemGrid
v-if="itemViewType === 'grid'"
:entry="item"
:highlight="true"
:mobile-handler="true"
@mouseup.stop.native="clickFilter"
@dragstart.native="$emit('dragstart')"
@drop.native="drop()"
@dragleave.native="dragLeave"
@dragover.prevent.native="dragEnter"
:class="{ 'border-theme': area }"
/>
</div>
</template>
<script>
import {events} from "../../bus";
import { events } from '../../bus'
import ItemList from './ItemList'
import ItemGrid from './ItemGrid'
import {mapGetters} from 'vuex'
import { mapGetters } from 'vuex'
export default {
name: 'ItemHandler',
props: [
'disableHighlight',
'item',
],
props: ['disableHighlight', 'item'],
components: {
ItemList,
ItemGrid,
ItemList,
ItemGrid,
},
computed: {
...mapGetters([
'isMultiSelectMode',
'itemViewType',
'clipboard',
'entries',
'user',
]),
...mapGetters(['isMultiSelectMode', 'itemViewType', 'clipboard', 'entries', 'user']),
isFolder() {
return this.item.data.type === 'folder'
},
@@ -76,40 +67,38 @@ export default {
return {
area: false,
delay: 220,
clicks: 0,
timer: null
delay: 220,
clicks: 0,
timer: null,
}
},
methods: {
clickFilter(e) {
clickFilter(e) {
// Handle click for mobile device
if (this.$isMobile()) {
this.clickedItem(e)
}
// Handle click for mobile device
if (this.$isMobile()) {
this.clickedItem(e)
}
// Handle click & double click for desktop
if (!this.$isMobile()) {
this.clicks++
// Handle click & double click for desktop
if (! this.$isMobile()) {
this.clicks++
if (this.clicks === 1) {
let self = this
if (this.clicks === 1) {
let self = this
this.timer = setTimeout(() => {
this.clickedItem(e)
self.clicks = 0
}, this.delay)
} else {
clearTimeout(this.timer)
this.timer = setTimeout(() => {
this.clickedItem(e)
self.clicks = 0
}, this.delay);
} else {
clearTimeout(this.timer);
this.goToItem(e)
this.clicks = 0;
}
}
},
drop() {
this.goToItem(e)
this.clicks = 0
}
}
},
drop() {
this.area = false
events.$emit('drop')
},
@@ -122,27 +111,24 @@ export default {
this.area = false
},
clickedItem(e) {
// Disabled right click
if (e.button === 2) return
// Disabled right click
if (e.button === 2) return
if (!this.$isMobile()) {
// After click deselect new folder rename input
if (document.getSelection().toString().length) {
document.getSelection().removeAllRanges();
}
if (document.getSelection().toString().length) {
document.getSelection().removeAllRanges()
}
if ((e.ctrlKey || e.metaKey) && !e.shiftKey) {
// Click + Ctrl
if (this.clipboard.some(item => item.data.id === this.item.data.id)) {
// Click + Ctrl
if (this.clipboard.some((item) => item.data.id === this.item.data.id)) {
this.$store.commit('REMOVE_ITEM_FROM_CLIPBOARD', this.item)
} else {
this.$store.commit('ADD_ITEM_TO_CLIPBOARD', this.item)
}
} else if (e.shiftKey) {
// Click + Shift
// Click + Shift
let lastItem = this.entries.indexOf(this.clipboard[this.clipboard.length - 1])
let clickedItem = this.entries.indexOf(this.item)
@@ -163,21 +149,17 @@ export default {
}
}
} else {
// Click
// Click
this.$store.commit('CLIPBOARD_CLEAR')
this.$store.commit('ADD_ITEM_TO_CLIPBOARD', this.item)
}
}
if (!this.isMultiSelectMode && this.$isMobile()) {
if (this.isFolder) {
this.$goToFileView(this.item.data.id)
this.$goToFileView(this.item.data.id)
} else {
if (this.isImage || this.isVideo || this.isAudio || this.isPdf) {
this.$store.commit('CLIPBOARD_CLEAR')
this.$store.commit('ADD_ITEM_TO_CLIPBOARD', this.item)
@@ -187,7 +169,7 @@ export default {
}
if (this.isMultiSelectMode && this.$isMobile()) {
if (this.clipboard.some(item => item.data.id === this.item.data.id)) {
if (this.clipboard.some((item) => item.data.id === this.item.data.id)) {
this.$store.commit('REMOVE_ITEM_FROM_CLIPBOARD', this.item)
} else {
this.$store.commit('ADD_ITEM_TO_CLIPBOARD', this.item)
@@ -196,20 +178,17 @@ export default {
},
goToItem() {
if (this.isImage || this.isVideo || this.isAudio || this.isPdf) {
this.$store.commit('CLIPBOARD_CLEAR')
this.$store.commit('ADD_ITEM_TO_CLIPBOARD', this.item)
this.$store.commit('CLIPBOARD_CLEAR')
this.$store.commit('ADD_ITEM_TO_CLIPBOARD', this.item)
events.$emit('file-preview:show')
} else if (this.isFile || !this.isFolder && !this.isVideo && !this.isAudio && !this.isImage) {
} else if (this.isFile || (!this.isFolder && !this.isVideo && !this.isAudio && !this.isImage)) {
this.$downloadFile(this.item.data.attributes.file_url, this.item.data.attributes.name + '.' + this.item.data.attributes.mimetype)
} else if (this.isFolder) {
this.$goToFileView(this.item.data.id)
this.$goToFileView(this.item.data.id)
}
},
}
},
}
</script>
@@ -217,7 +196,6 @@ export default {
@import '../../../sass/vuefilemanager/variables';
@import '../../../sass/vuefilemanager/mixins';
.slide-from-left-move {
transition: transform 300s ease;
}
@@ -357,7 +335,7 @@ export default {
height: 52px;
/deep/ .folder-icon {
@include font-size(52)
@include font-size(52);
}
}
@@ -430,7 +408,6 @@ export default {
}
.dark {
.file-wrapper {
.icon-item {
.file-icon {
@@ -446,15 +423,13 @@ export default {
background: $dark_mode_background !important;
.file-icon {
path {
fill: $dark_mode_foreground !important;
stroke: #2F3C54;
stroke: #2f3c54;
}
}
.item-name {
.name {
color: $dark_mode_text_primary !important;
}
@@ -485,4 +460,4 @@ export default {
}
}
}
</style>
</style>

View File

@@ -1,199 +1,195 @@
<template>
<div :class="{'dark:bg-dark-foreground bg-light-background': isClicked && highlight, 'dark:hover:bg-dark-foreground hover:bg-light-background': highlight}" class="flex items-center px-2.5 py-2 rounded-xl select-none border-2 border-transparent border-dashed" :draggable="canDrag" spellcheck="false">
<div
:class="{
'bg-light-background dark:bg-dark-foreground': isClicked && highlight,
'hover:bg-light-background dark:hover:bg-dark-foreground': highlight,
}"
class="flex select-none items-center rounded-xl border-2 border-dashed border-transparent px-2.5 py-2"
:draggable="canDrag"
spellcheck="false"
>
<!--MultiSelecting for the mobile version-->
<CheckBox v-if="isMultiSelectMode" v-model="isClicked" :is-clicked="isClicked" class="mr-5" />
<!--MultiSelecting for the mobile version-->
<CheckBox v-if="isMultiSelectMode" v-model="isClicked" :is-clicked="isClicked" class="mr-5"/>
<!--Item thumbnail-->
<div class="relative w-16">
<!--Member thumbnail for team folders-->
<MemberAvatar v-if="user && canShowAuthor" :size="28" :is-border="true" :member="entry.data.relationships.owner" class="absolute right-1.5 -bottom-2 z-10" />
<!--Item thumbnail-->
<div class="w-16 relative">
<!--Emoji Icon-->
<Emoji v-if="entry.data.attributes.emoji" :emoji="entry.data.attributes.emoji" class="ml-1 scale-110 transform text-5xl" />
<!--Member thumbnail for team folders-->
<MemberAvatar
v-if="user && canShowAuthor"
:size="28"
:is-border="true"
:member="entry.data.relationships.owner"
class="absolute right-1.5 -bottom-2 z-10"
/>
<!--Folder Icon-->
<FolderIcon v-if="isFolder && !entry.data.attributes.emoji" :item="entry" />
<!--Emoji Icon-->
<Emoji
v-if="entry.data.attributes.emoji"
:emoji="entry.data.attributes.emoji"
class="text-5xl ml-1 transform scale-110"
/>
<!--File Icon-->
<FileIconThumbnail v-if="isFile || isVideo || isAudio || (isImage && !entry.data.attributes.thumbnail)" :entry="entry" class="pr-2" />
<!--Folder Icon-->
<FolderIcon v-if="isFolder && !entry.data.attributes.emoji" :item="entry" />
<!--Image thumbnail-->
<img
v-if="isImage && entry.data.attributes.thumbnail"
class="ml-0.5 h-12 w-12 rounded object-cover"
:src="entry.data.attributes.thumbnail.xs"
:alt="entry.data.attributes.name"
loading="lazy"
/>
</div>
<!--File Icon-->
<FileIconThumbnail v-if="isFile || isVideo || isAudio || (isImage && !entry.data.attributes.thumbnail)" :entry="entry" class="pr-2" />
<!--Item Info-->
<div class="pl-2">
<!--Item Title-->
<b
class="mb-0.5 block overflow-hidden text-ellipsis whitespace-nowrap text-sm hover:underline"
style="max-width: 240px"
ref="name"
@input="renameItem"
@keydown.delete.stop
@click.stop
:contenteditable="canEditName"
>
{{ itemName }}
</b>
<!--Image thumbnail-->
<img v-if="isImage && entry.data.attributes.thumbnail" class="w-12 h-12 rounded ml-0.5 object-cover" :src="entry.data.attributes.thumbnail.xs" :alt="entry.data.attributes.name" loading="lazy" />
</div>
<!--Item sub line-->
<div class="flex items-center">
<!--Shared Icon-->
<div v-if="$checkPermission('master') && entry.data.relationships.shared">
<link-icon size="12" class="text-theme dark-text-theme vue-feather mr-1.5" />
</div>
<!--Item Info-->
<div class="pl-2">
<!--File & Image sub line-->
<small v-if="!isFolder" class="block text-xs text-gray-500"> {{ entry.data.attributes.filesize }}, {{ timeStamp }} </small>
<!--Item Title-->
<b class="block text-sm mb-0.5 text-ellipsis overflow-hidden hover:underline whitespace-nowrap" style="max-width: 240px" ref="name" @input="renameItem" @keydown.delete.stop @click.stop :contenteditable="canEditName">
{{ itemName }}
</b>
<!--Folder sub line-->
<small v-if="isFolder" class="block text-xs text-gray-500">
{{ folderItems === 0 ? $t('folder.empty') : $tc('folder.item_counts', folderItems) }}, {{ timeStamp }}
</small>
</div>
</div>
<!--Item sub line-->
<div class="flex items-center">
<!--Shared Icon-->
<div v-if="$checkPermission('master') && entry.data.relationships.shared">
<link-icon size="12" class="mr-1.5 text-theme dark-text-theme vue-feather"/>
</div>
<!--File & Image sub line-->
<small v-if="! isFolder" class="block text-xs text-gray-500">
{{ entry.data.attributes.filesize }}, {{ timeStamp }}
</small>
<!--Folder sub line-->
<small v-if="isFolder" class="block text-xs text-gray-500">
{{ folderItems === 0 ? $t('folder.empty') : $tc('folder.item_counts', folderItems) }}, {{ timeStamp }}
</small>
</div>
</div>
<!-- Mobile item action button-->
<div v-if="mobileHandler && ! isMultiSelectMode && $isMobile()" class="pr-1 flex-grow text-right relative">
<div @mouseup.stop="$openInDetailPanel(entry)" class="absolute right-10 p-2.5 -mr-4 transform -translate-y-2/4 lg:block hidden">
<eye-icon size="18" class="vue-feather opacity-30 inline-block" />
</div>
<div @mouseup.stop="showItemActions" class="absolute right-0 p-2.5 -mr-4 transform -translate-y-2/4">
<MoreVerticalIcon size="18" class="vue-feather text-theme dark-text-theme inline-block" />
</div>
</div>
</div>
<!-- Mobile item action button-->
<div v-if="mobileHandler && !isMultiSelectMode && $isMobile()" class="relative flex-grow pr-1 text-right">
<div @mouseup.stop="$openInDetailPanel(entry)" class="absolute right-10 -mr-4 hidden -translate-y-2/4 transform p-2.5 lg:block">
<eye-icon size="18" class="vue-feather inline-block opacity-30" />
</div>
<div @mouseup.stop="showItemActions" class="absolute right-0 -mr-4 -translate-y-2/4 transform p-2.5">
<MoreVerticalIcon size="18" class="vue-feather text-theme dark-text-theme inline-block" />
</div>
</div>
</div>
</template>
<script>
import Emoji from "../Others/Emoji";
import FolderIcon from "./FolderIcon";
import {LinkIcon, MoreVerticalIcon, EyeIcon} from 'vue-feather-icons'
import FileIconThumbnail from "./FileIconThumbnail";
import MemberAvatar from "./MemberAvatar";
import CheckBox from "./CheckBox";
import {debounce} from "lodash";
import {mapGetters} from "vuex";
import {events} from "../../bus";
import Emoji from '../Others/Emoji'
import FolderIcon from './FolderIcon'
import { LinkIcon, MoreVerticalIcon, EyeIcon } from 'vue-feather-icons'
import FileIconThumbnail from './FileIconThumbnail'
import MemberAvatar from './MemberAvatar'
import CheckBox from './CheckBox'
import { debounce } from 'lodash'
import { mapGetters } from 'vuex'
import { events } from '../../bus'
export default {
name: 'ItemList',
components: {
FileIconThumbnail,
MoreVerticalIcon,
MemberAvatar,
FolderIcon,
CheckBox,
LinkIcon,
EyeIcon,
Emoji,
},
props: [
'mobileHandler',
'highlight',
'entry',
],
data() {
return {
mobileMultiSelect: false,
itemName: undefined,
isSelected: false,
}
},
computed: {
...mapGetters([
'isMultiSelectMode',
'clipboard',
'user',
]),
isClicked() {
return this.clipboard.some(element => element.data.id === this.entry.data.id)
},
isVideo() {
return this.entry.data.type === 'video'
},
isAudio() {
return this.entry.data.type === 'audio'
},
isFile() {
return this.entry.data.type === 'file'
},
isImage() {
return this.entry.data.type === 'image'
},
isFolder() {
return this.entry.data.type === 'folder'
},
timeStamp() {
return this.entry.data.attributes.deleted_at
? this.$t('item_thumbnail.deleted_at', {time: this.entry.data.attributes.deleted_at})
: this.entry.data.attributes.created_at
},
canEditName() {
return !this.$isMobile()
&& !this.$isThisRoute(this.$route, ['Trash'])
&& !this.$checkPermission('visitor')
&& !(this.sharedDetail && this.sharedDetail.attributes.type === 'file')
},
folderItems() {
return this.entry.data.attributes.deleted_at
? this.entry.data.attributes.trashed_items
: this.entry.data.attributes.items
},
canShowAuthor() {
return !this.isFolder
&& this.user.data.id !== this.entry.data.relationships.owner.data.id
},
canDrag() {
return !this.isDeleted && this.$checkPermission(['master', 'editor'])
},
},
methods: {
showItemActions() {
this.$store.commit('CLIPBOARD_CLEAR')
this.$store.commit('ADD_ITEM_TO_CLIPBOARD', this.entry)
export default {
name: 'ItemList',
components: {
FileIconThumbnail,
MoreVerticalIcon,
MemberAvatar,
FolderIcon,
CheckBox,
LinkIcon,
EyeIcon,
Emoji,
},
props: ['mobileHandler', 'highlight', 'entry'],
data() {
return {
mobileMultiSelect: false,
itemName: undefined,
isSelected: false,
}
},
computed: {
...mapGetters(['isMultiSelectMode', 'clipboard', 'user']),
isClicked() {
return this.clipboard.some((element) => element.data.id === this.entry.data.id)
},
isVideo() {
return this.entry.data.type === 'video'
},
isAudio() {
return this.entry.data.type === 'audio'
},
isFile() {
return this.entry.data.type === 'file'
},
isImage() {
return this.entry.data.type === 'image'
},
isFolder() {
return this.entry.data.type === 'folder'
},
timeStamp() {
return this.entry.data.attributes.deleted_at
? this.$t('item_thumbnail.deleted_at', {
time: this.entry.data.attributes.deleted_at,
})
: this.entry.data.attributes.created_at
},
canEditName() {
return (
!this.$isMobile() &&
!this.$isThisRoute(this.$route, ['Trash']) &&
!this.$checkPermission('visitor') &&
!(this.sharedDetail && this.sharedDetail.attributes.type === 'file')
)
},
folderItems() {
return this.entry.data.attributes.deleted_at ? this.entry.data.attributes.trashed_items : this.entry.data.attributes.items
},
canShowAuthor() {
return !this.isFolder && this.user.data.id !== this.entry.data.relationships.owner.data.id
},
canDrag() {
return !this.isDeleted && this.$checkPermission(['master', 'editor'])
},
},
methods: {
showItemActions() {
this.$store.commit('CLIPBOARD_CLEAR')
this.$store.commit('ADD_ITEM_TO_CLIPBOARD', this.entry)
this.$showMobileMenu('file-menu')
events.$emit('mobile-context-menu:show', this.entry)
},
renameItem: debounce(function (e) {
this.$showMobileMenu('file-menu')
events.$emit('mobile-context-menu:show', this.entry)
},
renameItem: debounce(function (e) {
// Prevent submit empty string
if (e.target.innerText.trim() === '') return
// Prevent submit empty string
if (e.target.innerText.trim() === '') return
this.$store.dispatch('renameItem', {
id: this.entry.data.id,
type: this.entry.data.type,
name: e.target.innerText,
})
}, 300),
},
created() {
// Set item name to own component variable
this.itemName = this.entry.data.attributes.name
this.$store.dispatch('renameItem', {
id: this.entry.data.id,
type: this.entry.data.type,
name: e.target.innerText
})
}, 300)
},
created() {
// Change item name
events.$on('change:name', (item) => {
if (this.entry.data.id === item.id) this.itemName = item.name
})
// Set item name to own component variable
this.itemName = this.entry.data.attributes.name
// Change item name
events.$on('change:name', item => {
if (this.entry.data.id === item.id) this.itemName = item.name
})
// Autofocus after newly created folder
events.$on('newFolder:focus', id => {
if ( !this.$isMobile() && this.entry.data.id === id) {
this.$refs.name.focus()
document.execCommand('selectAll')
}
})
}
}
// Autofocus after newly created folder
events.$on('newFolder:focus', (id) => {
if (!this.$isMobile() && this.entry.data.id === id) {
this.$refs.name.focus()
document.execCommand('selectAll')
}
})
},
}
</script>

View File

@@ -1,62 +1,69 @@
<template>
<div class="shrink-0 grow-0">
<img
:style="{width: size + 'px', height: size + 'px'}"
v-if="member.data.attributes.avatar"
:src="avatar"
:class="[borderRadius, {'border-3 border-white dark:border-dark-background': isBorder}]"
class=""
/>
<div
v-else
class="flex items-center justify-center"
:class="[borderRadius, {'border-3 border-white dark:border-dark-background': isBorder}]"
:style="{width: size + 'px', height: size + 'px', background: member.data.attributes.color ? member.data.attributes.color : '#f4f5f6'}"
>
<span :class="fontSize" class="uppercase font-extrabold text-gray-900">
{{ letter }}
</span>
</div>
</div>
<div class="shrink-0 grow-0">
<img
:style="{ width: size + 'px', height: size + 'px' }"
v-if="member.data.attributes.avatar"
:src="avatar"
:class="[
borderRadius,
{
'border-3 border-white dark:border-dark-background': isBorder,
},
]"
class=""
/>
<div
v-else
class="flex items-center justify-center"
:class="[
borderRadius,
{
'border-3 border-white dark:border-dark-background': isBorder,
},
]"
:style="{
width: size + 'px',
height: size + 'px',
background: member.data.attributes.color ? member.data.attributes.color : '#f4f5f6',
}"
>
<span :class="fontSize" class="font-extrabold uppercase text-gray-900">
{{ letter }}
</span>
</div>
</div>
</template>
<script>
export default {
name: 'MemberAvatar',
props: ['isBorder', 'member', 'size'],
computed: {
letter() {
let string = this.member.data.attributes.name ? this.member.data.attributes.name : this.member.data.attributes.email
export default {
name: 'MemberAvatar',
props: [
'isBorder',
'member',
'size',
],
computed: {
letter() {
let string = this.member.data.attributes.name
? this.member.data.attributes.name
: this.member.data.attributes.email
return string.substr(0, 1)
},
borderRadius() {
return this.size > 32 ? 'rounded-xl' : 'rounded-lg'
},
fontSize() {
if (this.size > 42) {
return 'text-lg'
} else if (this.size > 32) {
return 'text-base'
} else {
return 'text-sm'
}
},
avatar() {
if (this.size >= 52) {
return this.member.data.attributes.avatar.md
} else if (this.size > 32) {
return this.member.data.attributes.avatar.sm
} else {
return this.member.data.attributes.avatar.xs
}
},
}
}
return string.substr(0, 1)
},
borderRadius() {
return this.size > 32 ? 'rounded-xl' : 'rounded-lg'
},
fontSize() {
if (this.size > 42) {
return 'text-lg'
} else if (this.size > 32) {
return 'text-base'
} else {
return 'text-sm'
}
},
avatar() {
if (this.size >= 52) {
return this.member.data.attributes.avatar.md
} else if (this.size > 32) {
return this.member.data.attributes.avatar.sm
} else {
return this.member.data.attributes.avatar.xs
}
},
},
}
</script>

View File

@@ -1,5 +1,5 @@
<template>
<button class="inline-block dark:bg-2x-dark-foreground bg-light-background rounded-xl py-2 px-3.5 mr-2">
<button class="mr-2 inline-block rounded-xl bg-light-background py-2 px-3.5 dark:bg-2x-dark-foreground">
<div class="flex items-center">
<hard-drive-icon v-if="icon === 'hard-drive'" size="15" class="vue-feather dark-text-theme" />
<upload-cloud-icon v-if="icon === 'upload-cloud'" size="15" class="vue-feather dark-text-theme" />
@@ -7,7 +7,7 @@
<trash2-icon v-if="icon === 'trash2'" size="15" class="vue-feather dark-text-theme" />
<users-icon v-if="icon === 'users'" size="15" class="vue-feather dark-text-theme" />
<user-check-icon v-if="icon === 'user-check'" size="15" class="vue-feather dark-text-theme" />
<search-icon v-if="icon === 'search'" size="15" class="vue-feather dark-text-theme" />
<search-icon v-if="icon === 'search'" size="15" class="vue-feather dark-text-theme" />
<refresh-cw-icon v-if="icon === 'refresh'" size="15" class="vue-feather dark-text-theme" />
<download-icon v-if="icon === 'download'" size="15" class="vue-feather dark-text-theme" />
<copy-icon v-if="icon === 'copy'" size="15" class="vue-feather dark-text-theme" />
@@ -26,7 +26,7 @@
<sorting-icon v-if="icon === 'preview-sorting'" class="vue-feather dark-text-theme preview-sorting" />
<cloud-plus-icon v-if="icon === 'cloud-plus'" class="vue-feather dark-text-theme preview-sorting" />
<span v-if="$slots.default" class="font-bold text-sm ml-2">
<span v-if="$slots.default" class="ml-2 text-sm font-bold">
<slot></slot>
</span>
</div>
@@ -34,40 +34,61 @@
</template>
<script>
import { UserCheckIcon, HardDriveIcon, UploadCloudIcon, LinkIcon, Trash2Icon, UsersIcon, SearchIcon, RefreshCwIcon, DownloadIcon, CopyIcon, FilterIcon, DollarSignIcon, CheckIcon, XSquareIcon, CheckSquareIcon, FolderPlusIcon, ListIcon, GridIcon, TrashIcon, UserPlusIcon, PlusIcon, CreditCardIcon } from 'vue-feather-icons'
import CloudPlusIcon from "./Icons/CloudPlusIcon";
import SortingIcon from "./Icons/SortingIcon";
import {
UserCheckIcon,
HardDriveIcon,
UploadCloudIcon,
LinkIcon,
Trash2Icon,
UsersIcon,
SearchIcon,
RefreshCwIcon,
DownloadIcon,
CopyIcon,
FilterIcon,
DollarSignIcon,
CheckIcon,
XSquareIcon,
CheckSquareIcon,
FolderPlusIcon,
ListIcon,
GridIcon,
TrashIcon,
UserPlusIcon,
PlusIcon,
CreditCardIcon,
} from 'vue-feather-icons'
import CloudPlusIcon from './Icons/CloudPlusIcon'
import SortingIcon from './Icons/SortingIcon'
export default {
name: 'MobileActionButton',
props: [
'icon'
],
components: {
UserCheckIcon,
HardDriveIcon,
UploadCloudIcon,
LinkIcon,
Trash2Icon,
UsersIcon,
CheckSquareIcon,
DollarSignIcon,
CreditCardIcon,
FolderPlusIcon,
RefreshCwIcon,
CloudPlusIcon,
UserPlusIcon,
DownloadIcon,
SortingIcon,
XSquareIcon,
FilterIcon,
SearchIcon,
CheckIcon,
TrashIcon,
PlusIcon,
CopyIcon,
ListIcon,
GridIcon,
}
}
export default {
name: 'MobileActionButton',
props: ['icon'],
components: {
UserCheckIcon,
HardDriveIcon,
UploadCloudIcon,
LinkIcon,
Trash2Icon,
UsersIcon,
CheckSquareIcon,
DollarSignIcon,
CreditCardIcon,
FolderPlusIcon,
RefreshCwIcon,
CloudPlusIcon,
UserPlusIcon,
DownloadIcon,
SortingIcon,
XSquareIcon,
FilterIcon,
SearchIcon,
CheckIcon,
TrashIcon,
PlusIcon,
CopyIcon,
ListIcon,
GridIcon,
},
}
</script>

View File

@@ -4,79 +4,76 @@
<cloud-plus-icon class="icon dark-text-theme" size="15" />
<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
/>
<input @change="emmitFiles" v-show="false" id="file" type="file" name="files[]" multiple />
</label>
</div>
</button>
</template>
<script>
import { UploadCloudIcon } from 'vue-feather-icons'
import CloudPlusIcon from "./Icons/CloudPlusIcon";
import { UploadCloudIcon } from 'vue-feather-icons'
import CloudPlusIcon from './Icons/CloudPlusIcon'
export default {
name: 'MobileActionButtonUpload',
components: {
CloudPlusIcon,
UploadCloudIcon,
export default {
name: 'MobileActionButtonUpload',
components: {
CloudPlusIcon,
UploadCloudIcon,
},
methods: {
emmitFiles(e) {
this.$uploadFiles(e.target.files)
},
methods: {
emmitFiles(e) {
this.$uploadFiles(e.target.files)
}
}
}
},
}
</script>
<style scoped lang="scss">
@import '../../../sass/vuefilemanager/variables';
@import '../../../sass/vuefilemanager/mixins';
@import '../../../sass/vuefilemanager/variables';
@import '../../../sass/vuefilemanager/mixins';
.mobile-action-button {
background: $light_background;
margin-right: 8px;
border-radius: 8px;
padding: 7px 14px;
cursor: pointer;
border: none;
.flex {
display: flex;
align-items: center;
}
.icon {
vertical-align: middle;
margin-right: 10px;
@include font-size(14);
}
.label {
vertical-align: middle;
@include font-size(14);
font-weight: 700;
color: $text;
}
}
.dark {
.mobile-action-button {
background: $light_background;
margin-right: 8px;
border-radius: 8px;
padding: 7px 14px;
cursor: pointer;
border: none;
background: $dark_mode_foreground;
.flex {
display: flex;
align-items: center;
}
.icon {
vertical-align: middle;
margin-right: 10px;
@include font-size(14);
path,
line,
polyline,
rect,
circle {
color: inherit;
}
.label {
vertical-align: middle;
@include font-size(14);
font-weight: 700;
color: $text;
}
}
.dark {
.mobile-action-button {
background: $dark_mode_foreground;
path, line, polyline, rect, circle {
color: inherit;
}
.label {
color: $dark_mode_text_primary;
}
color: $dark_mode_text_primary;
}
}
}
</style>

View File

@@ -2,37 +2,35 @@
<MenuMobile name="file-menu">
<ThumbnailItem class="m-5" :item="clipboard[0]" />
<MenuMobileGroup v-if="$slots.default">
<slot></slot>
<MenuMobileGroup v-if="$slots.default">
<slot></slot>
</MenuMobileGroup>
<MenuMobileGroup v-if="$slots.editor && $checkPermission('editor')">
<slot name="editor"></slot>
<MenuMobileGroup v-if="$slots.editor && $checkPermission('editor')">
<slot name="editor"></slot>
</MenuMobileGroup>
<MenuMobileGroup v-if="$slots.visitor && $checkPermission('visitor')">
<slot name="visitor"></slot>
<MenuMobileGroup v-if="$slots.visitor && $checkPermission('visitor')">
<slot name="visitor"></slot>
</MenuMobileGroup>
</MenuMobile>
</template>
<script>
import MenuMobileGroup from "../Mobile/MenuMobileGroup";
import ThumbnailItem from "../Others/ThumbnailItem";
import MenuMobile from "../Mobile/MenuMobile";
import {mapGetters} from 'vuex'
import MenuMobileGroup from '../Mobile/MenuMobileGroup'
import ThumbnailItem from '../Others/ThumbnailItem'
import MenuMobile from '../Mobile/MenuMobile'
import { mapGetters } from 'vuex'
export default {
name: 'MobileContextMenu',
components: {
MenuMobileGroup,
ThumbnailItem,
MenuMobile,
MenuMobile,
},
computed: {
...mapGetters([
'clipboard',
]),
...mapGetters(['clipboard']),
},
}
</script>

View File

@@ -1,15 +1,15 @@
<template>
<MenuMobile @click.native.capture="closeMenu" name="create-list">
<MenuMobileGroup>
<slot />
<slot />
</MenuMobileGroup>
</MenuMobile>
</template>
<script>
import MenuMobileGroup from "../Mobile/MenuMobileGroup";
import MenuMobile from "../Mobile/MenuMobile";
import {events} from "../../bus";
import MenuMobileGroup from '../Mobile/MenuMobileGroup'
import MenuMobile from '../Mobile/MenuMobile'
import { events } from '../../bus'
export default {
name: 'MobileContextMenu',
@@ -18,9 +18,9 @@ export default {
MenuMobile,
},
methods: {
closeMenu() {
events.$emit('mobile-menu:hide')
},
}
closeMenu() {
events.$emit('mobile-menu:hide')
},
},
}
</script>

View File

@@ -1,9 +1,9 @@
<template>
<transition name="context-menu">
<div v-if="isMultiSelectMode" class="multiselect-actions">
<slot v-if="$slots.default" />
<slot v-if="$slots.editor && $checkPermission('editor')" name="editor" />
<slot v-if="$slots.visitor && $checkPermission('visitor')" name="visitor" />
<slot v-if="$slots.default" />
<slot v-if="$slots.editor && $checkPermission('editor')" name="editor" />
<slot v-if="$slots.visitor && $checkPermission('visitor')" name="visitor" />
<ToolbarButton @click.native="closeSelecting" class="action-btn close-icon" source="close" :action="$t('actions.close')" />
</div>
@@ -11,31 +11,28 @@
</template>
<script>
import ToolbarButton from "./ToolbarButton";
import {mapGetters} from 'vuex'
import ToolbarButton from './ToolbarButton'
import { mapGetters } from 'vuex'
export default {
name: 'MobileMultiSelectToolbar',
components: {
ToolbarButton,
},
ToolbarButton,
},
computed: {
...mapGetters([
'isMultiSelectMode',
'clipboard',
]),
...mapGetters(['isMultiSelectMode', 'clipboard']),
},
methods: {
closeSelecting() {
this.$store.commit('TOGGLE_MULTISELECT_MODE')
this.$store.commit('TOGGLE_MULTISELECT_MODE')
},
}
},
}
</script>
<style scoped lang="scss">
@import "resources/sass/vuefilemanager/_variables";
@import "resources/sass/vuefilemanager/_mixins";
@import 'resources/sass/vuefilemanager/_variables';
@import 'resources/sass/vuefilemanager/_mixins';
.multiselect-actions {
display: flex;
@@ -71,7 +68,6 @@ export default {
}
.options {
&.is-active {
opacity: 1 !important;
pointer-events: initial !important;
@@ -80,7 +76,6 @@ export default {
}
.dark {
.multiselect-actions {
background: $dark_mode_foreground;
}
@@ -111,5 +106,4 @@ export default {
.context-menu-leave-active {
position: absolute;
}
</style>

View File

@@ -1,24 +1,24 @@
<template>
<MenuMobile name="team-menu">
<TeamFolderPreview />
<TeamFolderPreview />
<MenuMobileGroup v-if="$slots.default">
<slot></slot>
<MenuMobileGroup v-if="$slots.default">
<slot></slot>
</MenuMobileGroup>
</MenuMobile>
</template>
<script>
import MenuMobileGroup from "../Mobile/MenuMobileGroup";
import MenuMobileGroup from '../Mobile/MenuMobileGroup'
import TeamFolderPreview from '../Teams/Components/TeamFolderPreview'
import MenuMobile from "../Mobile/MenuMobile";
import MenuMobile from '../Mobile/MenuMobile'
export default {
name: 'MobileTeamContextMenu',
components: {
TeamFolderPreview,
TeamFolderPreview,
MenuMobileGroup,
MenuMobile,
MenuMobile,
},
}
</script>

View File

@@ -1,90 +1,96 @@
<template>
<div class="sticky top-0 dark:bg-dark-background bg-white flex text-center py-5 px-4 w-full justify-between items-center z-20 lg:hidden block">
<div class="sticky top-0 z-20 block flex w-full items-center justify-between bg-white py-5 px-4 text-center dark:bg-dark-background lg:hidden">
<!-- Go back-->
<div @click="goBack" class="go-back-button flex text-left items-center">
<chevron-left-icon size="17" :class="{'opacity-0 -translate-x-3': ! isLoadedFolder, 'opacity-100 translate-x-0': isLoadedFolder }" class="transform align-middle cursor-pointer mr-2 -ml-1 transition-all duration-200" />
<div @click="goBack" class="go-back-button flex items-center text-left">
<chevron-left-icon
size="17"
:class="{
'-translate-x-3 opacity-0': !isLoadedFolder,
'translate-x-0 opacity-100': isLoadedFolder,
}"
class="mr-2 -ml-1 transform cursor-pointer align-middle transition-all duration-200"
/>
<!--Folder Title-->
<div :class="{'-translate-x-4': ! isLoadedFolder}" class="transform lg:text-base text-sm align-middle font-bold overflow-hidden text-ellipsis inline-block whitespace-nowrap transition-all duration-200" style="max-width: 200px;">
{{ $getCurrentLocationName() }}
</div>
<!--Folder Title-->
<div
:class="{ '-translate-x-4': !isLoadedFolder }"
class="inline-block transform overflow-hidden text-ellipsis whitespace-nowrap align-middle text-sm font-bold transition-all duration-200 lg:text-base"
style="max-width: 200px"
>
{{ $getCurrentLocationName() }}
</div>
<span @click.stop="showItemActions" :class="{'-translate-x-4 opacity-0': ! currentFolder, 'translate-x-0 opacity-100': currentFolder}" class="transform py-0.5 px-1.5 ml-3 rounded-md dark:bg-dark-foreground bg-light-background transition-all duration-200">
<more-horizontal-icon size="14" />
</span>
<span
@click.stop="showItemActions"
:class="{
'-translate-x-4 opacity-0': !currentFolder,
'translate-x-0 opacity-100': currentFolder,
}"
class="ml-3 transform rounded-md bg-light-background py-0.5 px-1.5 transition-all duration-200 dark:bg-dark-foreground"
>
<more-horizontal-icon size="14" />
</span>
</div>
<div class="flex items-center relative">
<TeamMembersButton
v-if="$isThisRoute($route, ['TeamFolders', 'SharedWithMe'])"
size="28"
@click.stop.native="$showMobileMenu('team-menu')"
class="absolute right-9"
/>
<div class="relative flex items-center">
<TeamMembersButton v-if="$isThisRoute($route, ['TeamFolders', 'SharedWithMe'])" size="28" @click.stop.native="$showMobileMenu('team-menu')" class="absolute right-9" />
<!--More Actions-->
<div class="relative">
<div v-if="$checkPermission('master')" @click="showMobileNavigation" class="absolute right-0 p-4 -mr-2 transform -translate-y-2/4">
<menu-icon size="17" />
</div>
</div>
</div>
<!--More Actions-->
<div class="relative">
<div v-if="$checkPermission('master')" @click="showMobileNavigation" class="absolute right-0 -mr-2 -translate-y-2/4 transform p-4">
<menu-icon size="17" />
</div>
</div>
</div>
</div>
</template>
<script>
import TeamMembersPreview from "../Teams/Components/TeamMembersPreview";
import TeamMembersButton from "../Teams/Components/TeamMembersButton";
import ToolbarButton from "./ToolbarButton";
import SearchBar from "./SearchBar";
import {MenuIcon, ChevronLeftIcon, MoreHorizontalIcon } from 'vue-feather-icons'
import {mapGetters} from 'vuex'
import {events} from "../../bus";
import TeamMembersPreview from '../Teams/Components/TeamMembersPreview'
import TeamMembersButton from '../Teams/Components/TeamMembersButton'
import ToolbarButton from './ToolbarButton'
import SearchBar from './SearchBar'
import { MenuIcon, ChevronLeftIcon, MoreHorizontalIcon } from 'vue-feather-icons'
import { mapGetters } from 'vuex'
import { events } from '../../bus'
export default {
name: 'MobileToolBar',
components: {
TeamMembersPreview,
MoreHorizontalIcon,
TeamMembersButton,
ChevronLeftIcon,
ToolbarButton,
SearchBar,
MenuIcon,
export default {
name: 'MobileToolBar',
components: {
TeamMembersPreview,
MoreHorizontalIcon,
TeamMembersButton,
ChevronLeftIcon,
ToolbarButton,
SearchBar,
MenuIcon,
},
computed: {
...mapGetters(['currentTeamFolder', 'isVisibleSidebar', 'currentFolder', 'itemViewType', 'clipboard']),
isLoadedFolder() {
return this.$route.params.id
},
computed: {
...mapGetters([
'currentTeamFolder',
'isVisibleSidebar',
'currentFolder',
'itemViewType',
'clipboard',
]),
isLoadedFolder() {
return this.$route.params.id
},
},
methods: {
showItemActions() {
this.$store.commit('CLIPBOARD_CLEAR')
this.$store.commit('ADD_ITEM_TO_CLIPBOARD', this.currentFolder)
},
methods: {
showItemActions() {
this.$store.commit('CLIPBOARD_CLEAR')
this.$store.commit('ADD_ITEM_TO_CLIPBOARD', this.currentFolder)
this.$showMobileMenu('file-menu')
events.$emit('mobile-context-menu:show', this.currentFolder)
},
showMobileNavigation() {
this.$showMobileMenu('user-navigation')
this.$store.commit('DISABLE_MULTISELECT_MODE')
},
goBack() {
if (this.isLoadedFolder) this.$router.back()
},
this.$showMobileMenu('file-menu')
events.$emit('mobile-context-menu:show', this.currentFolder)
},
created() {
events.$on('show:content', () => {
if (this.isSidebarMenu) this.isSidebarMenu = false
})
}
}
showMobileNavigation() {
this.$showMobileMenu('user-navigation')
this.$store.commit('DISABLE_MULTISELECT_MODE')
},
goBack() {
if (this.isLoadedFolder) this.$router.back()
},
},
created() {
events.$on('show:content', () => {
if (this.isSidebarMenu) this.isSidebarMenu = false
})
},
}
</script>

View File

@@ -1,63 +1,68 @@
<template>
<li class="2xl:py-4 xl:py-3 lg:py-2.5 py-4 px-5 flex items-center justify-between" :class="{'dark:hover:bg-4x-dark-foreground hover:bg-light-background cursor-pointer group': ! isHoverDisabled}">
<li
class="flex items-center justify-between py-4 px-5 lg:py-2.5 xl:py-3 2xl:py-4"
:class="{
'group cursor-pointer hover:bg-light-background dark:hover:bg-4x-dark-foreground': !isHoverDisabled,
}"
>
<div class="flex items-center">
<div class="mr-4">
<calendar-icon v-if="icon === 'calendar'" size="17" class="vue-feather group-hover-text-theme" :class="{'text-theme': isActive}"/>
<grid-icon v-if="icon === 'grid'" size="17" class="vue-feather group-hover-text-theme" :class="{'text-theme': isActive}"/>
<list-icon v-if="icon === 'list'" size="17" class="vue-feather group-hover-text-theme" :class="{'text-theme': isActive}"/>
<trash-2-icon v-if="icon === 'trash'" size="17" class="vue-feather group-hover-text-theme" :class="{'text-theme': isActive}"/>
<life-buoy-icon v-if="icon === 'restore'" size="17" class="vue-feather group-hover-text-theme" :class="{'text-theme': isActive}"/>
<trash-icon v-if="icon === 'empty-trash'" size="17" class="vue-feather group-hover-text-theme" :class="{'text-theme': isActive}"/>
<eye-icon v-if="icon ==='detail'" size="17" class="vue-feather group-hover-text-theme" :class="{'text-theme': isActive}"/>
<download-cloud-icon v-if="icon === 'download'" size="17" class="vue-feather group-hover-text-theme" :class="{'text-theme': isActive}"/>
<edit2-icon v-if="icon === 'rename'" size="17" class="vue-feather group-hover-text-theme" :class="{'text-theme': isActive}"/>
<corner-down-right-icon v-if="icon === 'move-item'" size="17" class="vue-feather group-hover-text-theme" :class="{'text-theme': isActive}"/>
<link-icon v-if="icon === 'share'" size="17" class="vue-feather group-hover-text-theme" :class="{'text-theme': isActive}"/>
<star-icon v-if="icon === 'favourites'" size="17" class="vue-feather group-hover-text-theme" :class="{'text-theme': isActive}"/>
<folder-plus-icon v-if="icon === 'create-folder'" size="17" class="vue-feather group-hover-text-theme" :class="{'text-theme': isActive}"/>
<smile-icon v-if="icon === 'no-options'" size="17" class="vue-feather group-hover-text-theme" :class="{'text-theme': isActive}"/>
<paperclip-icon v-if="icon === 'zip-folder'" size="17" class="vue-feather group-hover-text-theme" :class="{'text-theme': isActive}"/>
<alphabet-icon v-if="icon === 'alphabet'" size="17" class="vue-feather group-hover-text-theme" :class="{'text-theme': isActive}"/>
<star-icon v-if="icon === 'star'" size="17" class="vue-feather group-hover-text-theme" :class="{'text-theme': isActive}"/>
<hard-drive-icon v-if="icon === 'hard-drive'" size="17" class="vue-feather group-hover-text-theme" :class="{'text-theme': isActive}"/>
<upload-cloud-icon v-if="icon === 'upload-cloud'" size="17" class="vue-feather group-hover-text-theme" :class="{'text-theme': isActive}"/>
<users-icon v-if="icon === 'users'" size="17" class="vue-feather group-hover-text-theme" :class="{'text-theme': isActive}"/>
<user-icon v-if="icon === 'user'" size="17" class="vue-feather group-hover-text-theme" :class="{'text-theme': isActive}"/>
<user-plus-icon v-if="icon === 'user-plus'" size="17" class="vue-feather group-hover-text-theme" :class="{'text-theme': isActive}"/>
<user-minus-icon v-if="icon === 'user-minus'" size="17" class="vue-feather group-hover-text-theme" :class="{'text-theme': isActive}"/>
<user-check-icon v-if="icon === 'user-check'" size="17" class="vue-feather group-hover-text-theme" :class="{'text-theme': isActive}"/>
<settings-icon v-if="icon === 'settings'" size="17" class="vue-feather group-hover-text-theme" :class="{'text-theme': isActive}"/>
<power-icon v-if="icon === 'power'" size="17" class="vue-feather group-hover-text-theme" :class="{'text-theme': isActive}"/>
<lock-icon v-if="icon === 'lock'" size="17" class="vue-feather group-hover-text-theme" :class="{'text-theme': isActive}"/>
<cloud-icon v-if="icon === 'cloud'" size="17" class="vue-feather group-hover-text-theme" :class="{'text-theme': isActive}"/>
<credit-card-icon v-if="icon === 'credit-card'" size="17" class="vue-feather group-hover-text-theme" :class="{'text-theme': isActive}"/>
<file-text-icon v-if="icon === 'file-text'" size="17" class="vue-feather group-hover-text-theme" :class="{'text-theme': isActive}"/>
<database-icon v-if="icon === 'database'" size="17" class="vue-feather group-hover-text-theme" :class="{'text-theme': isActive}"/>
<globe-icon v-if="icon === 'globe'" size="17" class="vue-feather group-hover-text-theme" :class="{'text-theme': isActive}"/>
<monitor-icon v-if="icon === 'monitor'" size="17" class="vue-feather group-hover-text-theme" :class="{'text-theme': isActive}"/>
<box-icon v-if="icon === 'box'" size="17" class="vue-feather group-hover-text-theme" :class="{'text-theme': isActive}"/>
<folder-plus-icon v-if="icon === 'folder-plus'" size="17" class="vue-feather group-hover-text-theme" :class="{'text-theme': isActive}"/>
</div>
<b class="font-bold text-sm group-hover-text-theme" :class="{'text-theme': isActive}">
{{ title }}
</b>
</div>
<div class="mr-4">
<calendar-icon v-if="icon === 'calendar'" size="17" class="vue-feather group-hover-text-theme" :class="{ 'text-theme': isActive }" />
<grid-icon v-if="icon === 'grid'" size="17" class="vue-feather group-hover-text-theme" :class="{ 'text-theme': isActive }" />
<list-icon v-if="icon === 'list'" size="17" class="vue-feather group-hover-text-theme" :class="{ 'text-theme': isActive }" />
<trash-2-icon v-if="icon === 'trash'" size="17" class="vue-feather group-hover-text-theme" :class="{ 'text-theme': isActive }" />
<life-buoy-icon v-if="icon === 'restore'" size="17" class="vue-feather group-hover-text-theme" :class="{ 'text-theme': isActive }" />
<trash-icon v-if="icon === 'empty-trash'" size="17" class="vue-feather group-hover-text-theme" :class="{ 'text-theme': isActive }" />
<eye-icon v-if="icon === 'detail'" size="17" class="vue-feather group-hover-text-theme" :class="{ 'text-theme': isActive }" />
<download-cloud-icon v-if="icon === 'download'" size="17" class="vue-feather group-hover-text-theme" :class="{ 'text-theme': isActive }" />
<edit2-icon v-if="icon === 'rename'" size="17" class="vue-feather group-hover-text-theme" :class="{ 'text-theme': isActive }" />
<corner-down-right-icon v-if="icon === 'move-item'" size="17" class="vue-feather group-hover-text-theme" :class="{ 'text-theme': isActive }" />
<link-icon v-if="icon === 'share'" size="17" class="vue-feather group-hover-text-theme" :class="{ 'text-theme': isActive }" />
<star-icon v-if="icon === 'favourites'" size="17" class="vue-feather group-hover-text-theme" :class="{ 'text-theme': isActive }" />
<folder-plus-icon v-if="icon === 'create-folder'" size="17" class="vue-feather group-hover-text-theme" :class="{ 'text-theme': isActive }" />
<smile-icon v-if="icon === 'no-options'" size="17" class="vue-feather group-hover-text-theme" :class="{ 'text-theme': isActive }" />
<paperclip-icon v-if="icon === 'zip-folder'" size="17" class="vue-feather group-hover-text-theme" :class="{ 'text-theme': isActive }" />
<alphabet-icon v-if="icon === 'alphabet'" size="17" class="vue-feather group-hover-text-theme" :class="{ 'text-theme': isActive }" />
<star-icon v-if="icon === 'star'" size="17" class="vue-feather group-hover-text-theme" :class="{ 'text-theme': isActive }" />
<hard-drive-icon v-if="icon === 'hard-drive'" size="17" class="vue-feather group-hover-text-theme" :class="{ 'text-theme': isActive }" />
<upload-cloud-icon v-if="icon === 'upload-cloud'" size="17" class="vue-feather group-hover-text-theme" :class="{ 'text-theme': isActive }" />
<users-icon v-if="icon === 'users'" size="17" class="vue-feather group-hover-text-theme" :class="{ 'text-theme': isActive }" />
<user-icon v-if="icon === 'user'" size="17" class="vue-feather group-hover-text-theme" :class="{ 'text-theme': isActive }" />
<user-plus-icon v-if="icon === 'user-plus'" size="17" class="vue-feather group-hover-text-theme" :class="{ 'text-theme': isActive }" />
<user-minus-icon v-if="icon === 'user-minus'" size="17" class="vue-feather group-hover-text-theme" :class="{ 'text-theme': isActive }" />
<user-check-icon v-if="icon === 'user-check'" size="17" class="vue-feather group-hover-text-theme" :class="{ 'text-theme': isActive }" />
<settings-icon v-if="icon === 'settings'" size="17" class="vue-feather group-hover-text-theme" :class="{ 'text-theme': isActive }" />
<power-icon v-if="icon === 'power'" size="17" class="vue-feather group-hover-text-theme" :class="{ 'text-theme': isActive }" />
<lock-icon v-if="icon === 'lock'" size="17" class="vue-feather group-hover-text-theme" :class="{ 'text-theme': isActive }" />
<cloud-icon v-if="icon === 'cloud'" size="17" class="vue-feather group-hover-text-theme" :class="{ 'text-theme': isActive }" />
<credit-card-icon v-if="icon === 'credit-card'" size="17" class="vue-feather group-hover-text-theme" :class="{ 'text-theme': isActive }" />
<file-text-icon v-if="icon === 'file-text'" size="17" class="vue-feather group-hover-text-theme" :class="{ 'text-theme': isActive }" />
<database-icon v-if="icon === 'database'" size="17" class="vue-feather group-hover-text-theme" :class="{ 'text-theme': isActive }" />
<globe-icon v-if="icon === 'globe'" size="17" class="vue-feather group-hover-text-theme" :class="{ 'text-theme': isActive }" />
<monitor-icon v-if="icon === 'monitor'" size="17" class="vue-feather group-hover-text-theme" :class="{ 'text-theme': isActive }" />
<box-icon v-if="icon === 'box'" size="17" class="vue-feather group-hover-text-theme" :class="{ 'text-theme': isActive }" />
<folder-plus-icon v-if="icon === 'folder-plus'" size="17" class="vue-feather group-hover-text-theme" :class="{ 'text-theme': isActive }" />
</div>
<b class="group-hover-text-theme text-sm font-bold" :class="{ 'text-theme': isActive }">
{{ title }}
</b>
</div>
<div v-if="arrow" class="ml-2">
<chevron-right-icon v-if="arrow === 'right'" size="14" class="vue-feather group-hover-text-theme opacity-50" :class="{'text-theme': isActive}"/>
<arrow-up-icon v-if="arrow === 'up'" size="14" class="vue-feather group-hover-text-theme opacity-50" :class="{'text-theme': isActive}"/>
<arrow-down-icon v-if="arrow === 'down'" size="14" class="vue-feather group-hover-text-theme opacity-50" :class="{'text-theme': isActive}"/>
<chevron-right-icon v-if="arrow === 'right'" size="14" class="vue-feather group-hover-text-theme opacity-50" :class="{ 'text-theme': isActive }" />
<arrow-up-icon v-if="arrow === 'up'" size="14" class="vue-feather group-hover-text-theme opacity-50" :class="{ 'text-theme': isActive }" />
<arrow-down-icon v-if="arrow === 'down'" size="14" class="vue-feather group-hover-text-theme opacity-50" :class="{ 'text-theme': isActive }" />
</div>
</li>
</template>
<script>
import AlphabetIcon from "./Icons/AlphabetIcon";
import AlphabetIcon from './Icons/AlphabetIcon'
import {
UserMinusIcon,
UserCheckIcon,
UserPlusIcon,
ArrowUpIcon,
ArrowDownIcon,
UserMinusIcon,
UserCheckIcon,
UserPlusIcon,
ArrowUpIcon,
ArrowDownIcon,
ChevronRightIcon,
BoxIcon,
MonitorIcon,
@@ -90,52 +95,46 @@ import {
DatabaseIcon,
} from 'vue-feather-icons'
export default {
name: 'Option',
props:[
'isHoverDisabled',
'isActive',
'title',
'arrow',
'icon'
],
components: {
UserMinusIcon,
UserCheckIcon,
UserPlusIcon,
ArrowUpIcon,
ArrowDownIcon,
BoxIcon,
MonitorIcon,
GlobeIcon,
DatabaseIcon,
ChevronRightIcon,
FileTextIcon,
CreditCardIcon,
CloudIcon,
LockIcon,
CornerDownRightIcon,
DownloadCloudIcon,
UploadCloudIcon,
FolderPlusIcon,
HardDriveIcon,
PaperclipIcon,
SettingsIcon,
LifeBuoyIcon,
CalendarIcon,
AlphabetIcon,
Trash2Icon,
SmileIcon,
PowerIcon,
UsersIcon,
Edit2Icon,
TrashIcon,
LinkIcon,
StarIcon,
GridIcon,
ListIcon,
UserIcon,
EyeIcon,
}
}
export default {
name: 'Option',
props: ['isHoverDisabled', 'isActive', 'title', 'arrow', 'icon'],
components: {
UserMinusIcon,
UserCheckIcon,
UserPlusIcon,
ArrowUpIcon,
ArrowDownIcon,
BoxIcon,
MonitorIcon,
GlobeIcon,
DatabaseIcon,
ChevronRightIcon,
FileTextIcon,
CreditCardIcon,
CloudIcon,
LockIcon,
CornerDownRightIcon,
DownloadCloudIcon,
UploadCloudIcon,
FolderPlusIcon,
HardDriveIcon,
PaperclipIcon,
SettingsIcon,
LifeBuoyIcon,
CalendarIcon,
AlphabetIcon,
Trash2Icon,
SmileIcon,
PowerIcon,
UsersIcon,
Edit2Icon,
TrashIcon,
LinkIcon,
StarIcon,
GridIcon,
ListIcon,
UserIcon,
EyeIcon,
},
}
</script>

View File

@@ -5,20 +5,19 @@
</template>
<script>
export default {
name: 'OptionGroup'
}
export default {
name: 'OptionGroup',
}
</script>
<style scoped lang="scss">
.option-group {
.option-group {
&:first-child {
padding-top: 0 !important;
}
&:first-child {
padding-top: 0 !important;
}
&:last-child {
padding-bottom: 0 !important;
}
}
&:last-child {
padding-bottom: 0 !important;
}
}
</style>

View File

@@ -1,63 +1,41 @@
<template>
<label class="menu-option group">
<div class="icon-left group-hover-text-theme">
<upload-cloud-icon v-if="type === 'file'" size="17" class="group-hover-text-theme"/>
<folder-upload-icon v-if="type === 'folder'" size="17" class="group-hover-text-theme"/>
<upload-cloud-icon v-if="type === 'file'" size="17" class="group-hover-text-theme" />
<folder-upload-icon v-if="type === 'folder'" size="17" class="group-hover-text-theme" />
</div>
<div class="text-label group-hover-text-theme">
{{ title }}
<input
v-if="type === 'file'"
@change="emmitFiles"
v-show="false"
id="file"
type="file"
name="files[]"
multiple
/>
<input v-if="type === 'file'" @change="emmitFiles" v-show="false" id="file" type="file" name="files[]" multiple />
<input
v-if="type === 'folder'"
@change="emmitFiles"
v-show="false"
id="folder"
type="file"
name="folders[]"
webkitdirectory
mozdirectory
/>
<input v-if="type === 'folder'" @change="emmitFiles" v-show="false" id="folder" type="file" name="folders[]" webkitdirectory mozdirectory />
</div>
</label>
</template>
<script>
import FolderUploadIcon from "./Icons/FolderUploadIcon";
import {
UploadCloudIcon,
} from 'vue-feather-icons'
import FolderUploadIcon from './Icons/FolderUploadIcon'
import { UploadCloudIcon } from 'vue-feather-icons'
export default {
name: 'Option',
props:[
'title',
'type',
],
components: {
FolderUploadIcon,
UploadCloudIcon,
export default {
name: 'Option',
props: ['title', 'type'],
components: {
FolderUploadIcon,
UploadCloudIcon,
},
methods: {
emmitFiles(e) {
this.$uploadFiles(e.target.files)
},
methods: {
emmitFiles(e) {
this.$uploadFiles(e.target.files)
}
}
}
},
}
</script>
<style scoped lang="scss">
@import "resources/sass/vuefilemanager/_variables";
@import "resources/sass/vuefilemanager/_mixins";
@import 'resources/sass/vuefilemanager/_variables';
@import 'resources/sass/vuefilemanager/_mixins';
.menu-option {
white-space: nowrap;
@@ -94,14 +72,12 @@ import {
}
.dark {
.menu-option {
color: $dark_mode_text_primary;
&:hover {
&:hover {
background: lighten($dark_mode_foreground, 2%);
}
}
}
}
</style>

View File

@@ -4,7 +4,7 @@
<div class="popup-wrapper">
<div class="popup-content">
<div class="spinner-wrapper">
<Spinner/>
<Spinner />
</div>
<h1 class="title">{{ processingPopup.title }}</h1>
<p class="message">{{ processingPopup.message }}</p>
@@ -15,19 +15,17 @@
</template>
<script>
import Spinner from "./Spinner";
import Spinner from './Spinner'
import { mapGetters } from 'vuex'
export default {
name: 'ProcessingPopup',
components: {
Spinner
Spinner,
},
computed: {
...mapGetters([
'processingPopup'
])
}
...mapGetters(['processingPopup']),
},
}
</script>
@@ -68,7 +66,6 @@ export default {
}
.popup-content {
.title {
@include font-size(22);
font-weight: 700;
@@ -90,7 +87,6 @@ export default {
}
.popup-content {
.title {
@include font-size(19);
}

View File

@@ -1,46 +1,44 @@
<template>
<div class="progress-bar">
<span class="bg-theme" :style="{ width: progress + '%' }"></span>
</div>
<div class="progress-bar">
<span class="bg-theme" :style="{ width: progress + '%' }"></span>
</div>
</template>
<script>
export default {
name: 'ProgressBar',
props: ['progress']
name: 'ProgressBar',
props: ['progress'],
}
</script>
<style scoped lang="scss">
@import '../../../sass/vuefilemanager/variables';
@import '../../../sass/vuefilemanager/mixins';
@import '../../../sass/vuefilemanager/variables';
@import '../../../sass/vuefilemanager/mixins';
.progress-bar {
width: 100%;
height: 5px;
background: $light_background;
margin-top: 6px;
border-radius: 10px;
.progress-bar {
width: 100%;
height: 5px;
background: $light_background;
margin-top: 6px;
border-radius: 10px;
span {
display: block;
height: 100%;
border-radius: 10px;
max-width: 100%;
}
}
span {
display: block;
height: 100%;
border-radius: 10px;
max-width: 100%;
}
}
.dark {
.dark {
.progress-bar {
background: $dark_mode_foreground;
}
}
.progress-bar {
background: $dark_mode_foreground;
}
}
@media only screen and (min-width: 680px) {
.dark .progress-bar {
background: $dark_mode_foreground;
}
}
@media only screen and (min-width: 680px) {
.dark .progress-bar {
background: $dark_mode_foreground;
}
}
</style>

View File

@@ -1,31 +1,31 @@
<template>
<div @click="$openSpotlight()" class="relative dark:bg-dark-foreground bg-light-background rounded-lg cursor-pointer">
<div class="flex justify-between items-center px-5 py-2.5 xl:w-72 w-56 text-left">
<div class="flex items-center">
<search-icon size="18" class="vue-feather dark:text-gray-600 text-gray-400" />
<span class="font-bold xl:text-sm text-xs dark:text-gray-600 text-gray-400 pl-2.5">
{{ $t('inputs.placeholder_search_files') }}
</span>
</div>
<span class="font-bold xl:text-sm text-xs dark:text-gray-600 text-gray-400 dark:border-opacity-5 border rounded px-1 py-0.5 tracking-normal">
{{ metaKeyIcon }}+K
</span>
</div>
<div @click="$openSpotlight()" class="relative cursor-pointer rounded-lg bg-light-background dark:bg-dark-foreground">
<div class="flex w-56 items-center justify-between px-5 py-2.5 text-left xl:w-72">
<div class="flex items-center">
<search-icon size="18" class="vue-feather text-gray-400 dark:text-gray-600" />
<span class="pl-2.5 text-xs font-bold text-gray-400 dark:text-gray-600 xl:text-sm">
{{ $t('inputs.placeholder_search_files') }}
</span>
</div>
<span class="rounded border px-1 py-0.5 text-xs font-bold tracking-normal text-gray-400 dark:border-opacity-5 dark:text-gray-600 xl:text-sm">
{{ metaKeyIcon }}+K
</span>
</div>
</div>
</template>
<script>
import {SearchIcon} from 'vue-feather-icons'
import { SearchIcon } from 'vue-feather-icons'
export default {
name: 'SearchBar',
components: {
SearchIcon,
export default {
name: 'SearchBar',
components: {
SearchIcon,
},
computed: {
metaKeyIcon() {
return this.$isApple() ? '⌘' : '⊞'
},
computed: {
metaKeyIcon() {
return this.$isApple() ? '⌘' : '⊞'
},
},
}
},
}
</script>

View File

@@ -5,40 +5,40 @@
</template>
<script>
export default {
name: 'Spinner'
}
export default {
name: 'Spinner',
}
</script>
<style scoped lang="scss">
@import '../../../sass/vuefilemanager/variables';
@import '../../../sass/vuefilemanager/mixins';
@import '../../../sass/vuefilemanager/variables';
@import '../../../sass/vuefilemanager/mixins';
#loading-bar-spinner.spinner {
left: 50%;
margin-left: -20px;
top: 50%;
margin-top: -20px;
position: absolute;
z-index: 19 !important;
animation: loading-bar-spinner 400ms linear infinite;
}
#loading-bar-spinner.spinner {
left: 50%;
margin-left: -20px;
top: 50%;
margin-top: -20px;
position: absolute;
z-index: 19 !important;
animation: loading-bar-spinner 400ms linear infinite;
}
#loading-bar-spinner.spinner .spinner-icon {
width: 40px;
height: 40px;
border: solid 4px transparent;
//border-top-color: $theme !important;
//border-left-color: $theme !important;
border-radius: 50%;
}
#loading-bar-spinner.spinner .spinner-icon {
width: 40px;
height: 40px;
border: solid 4px transparent;
//border-top-color: $theme !important;
//border-left-color: $theme !important;
border-radius: 50%;
}
@keyframes loading-bar-spinner {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(360deg);
}
@keyframes loading-bar-spinner {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(360deg);
}
}
</style>

View File

@@ -2,44 +2,34 @@
<div class="flex items-start">
<div class="mr-2">
<CheckSquareIcon v-if="icon === 'check-square'" class="text-theme vue-feather" size="19" />
<image-icon v-if="icon === 'image'" class="text-theme vue-feather" size="19" />
<video-icon v-if="icon === 'video'" class="text-theme vue-feather" size="19" />
<folder-icon v-if="icon === 'folder'" class="text-theme vue-feather" size="19" />
<file-icon v-if="icon === 'file'" class="text-theme vue-feather" size="19" />
<image-icon v-if="icon === 'image'" class="text-theme vue-feather" size="19" />
<video-icon v-if="icon === 'video'" class="text-theme vue-feather" size="19" />
<folder-icon v-if="icon === 'folder'" class="text-theme vue-feather" size="19" />
<file-icon v-if="icon === 'file'" class="text-theme vue-feather" size="19" />
</div>
<div>
<b class="font-bold text-base inline-block whitespace-nowrap 2xl:w-72 w-52 text-ellipsis overflow-hidden leading-3">
{{ title }}
</b>
<small class="font-bold text-xs text-gray-400 block">
{{ subtitle }}
</small>
<b class="inline-block w-52 overflow-hidden text-ellipsis whitespace-nowrap text-base font-bold leading-3 2xl:w-72">
{{ title }}
</b>
<small class="block text-xs font-bold text-gray-400">
{{ subtitle }}
</small>
</div>
</div>
</template>
<script>
import {
CheckSquareIcon,
FolderIcon,
ImageIcon,
VideoIcon,
FileIcon,
} from "vue-feather-icons"
import { CheckSquareIcon, FolderIcon, ImageIcon, VideoIcon, FileIcon } from 'vue-feather-icons'
export default {
name: 'TitlePreview',
props: [
'subtitle',
'title',
'icon',
],
components: {
CheckSquareIcon,
FolderIcon,
ImageIcon,
VideoIcon,
FileIcon,
},
}
export default {
name: 'TitlePreview',
props: ['subtitle', 'title', 'icon'],
components: {
CheckSquareIcon,
FolderIcon,
ImageIcon,
VideoIcon,
FileIcon,
},
}
</script>

View File

@@ -1,32 +1,56 @@
<template>
<button class="button hover-text-theme hover-svg-stroke-theme" :title="action">
<corner-down-right-icon v-if="source === 'move'" size="19" class="hover-text-theme" />
<download-cloud-icon v-if="source === 'download'" size="19" class="hover-text-theme" />
<folder-plus-icon v-if="source === 'folder-plus'" size="19" class="hover-text-theme" />
<user-plus-icon v-if="source === 'user-plus'" size="19" class="hover-text-theme" />
<zoom-in-icon v-if="source === 'zoom-in'" size="19" />
<zoom-out-icon v-if="source === 'zoom-out'" size="19" />
<edit-2-icon v-if="source === 'rename'" size="19" />
<printer-icon v-if="source === 'print'" size="19" />
<trash-2-icon v-if="source === 'trash'" size="19" />
<list-icon v-if="source === 'th-list'" size="19" />
<info-icon v-if="source === 'info'" size="19" />
<grid-icon v-if="source === 'th'" size="19" />
<link-icon v-if="source === 'share'" size="19" />
<x-icon v-if="source === 'close'" size="19" />
<search-icon v-if="source === 'search'" size="19" />
<cloud-off-icon v-if="source === 'shared-off'" size="19" />
<sorting-icon v-if="source === 'preview-sorting'" class="preview-sorting"/>
<CloudPlusIcon v-if="source === 'cloud-plus'" class="preview-sorting"/>
</button>
<button class="button hover-text-theme hover-svg-stroke-theme" :title="action">
<corner-down-right-icon v-if="source === 'move'" size="19" class="hover-text-theme" />
<download-cloud-icon v-if="source === 'download'" size="19" class="hover-text-theme" />
<folder-plus-icon v-if="source === 'folder-plus'" size="19" class="hover-text-theme" />
<user-plus-icon v-if="source === 'user-plus'" size="19" class="hover-text-theme" />
<zoom-in-icon v-if="source === 'zoom-in'" size="19" />
<zoom-out-icon v-if="source === 'zoom-out'" size="19" />
<edit-2-icon v-if="source === 'rename'" size="19" />
<printer-icon v-if="source === 'print'" size="19" />
<trash-2-icon v-if="source === 'trash'" size="19" />
<list-icon v-if="source === 'th-list'" size="19" />
<info-icon v-if="source === 'info'" size="19" />
<grid-icon v-if="source === 'th'" size="19" />
<link-icon v-if="source === 'share'" size="19" />
<x-icon v-if="source === 'close'" size="19" />
<search-icon v-if="source === 'search'" size="19" />
<cloud-off-icon v-if="source === 'shared-off'" size="19" />
<sorting-icon v-if="source === 'preview-sorting'" class="preview-sorting" />
<CloudPlusIcon v-if="source === 'cloud-plus'" class="preview-sorting" />
</button>
</template>
<script>
import SortingIcon from "./Icons/SortingIcon";
import CloudPlusIcon from "./Icons/CloudPlusIcon";
import {
SearchIcon,
UserPlusIcon,
import SortingIcon from './Icons/SortingIcon'
import CloudPlusIcon from './Icons/CloudPlusIcon'
import {
SearchIcon,
UserPlusIcon,
CornerDownRightIcon,
DownloadCloudIcon,
FolderPlusIcon,
CloudOffIcon,
PrinterIcon,
ZoomOutIcon,
ZoomInIcon,
Trash2Icon,
Edit2Icon,
GridIcon,
ListIcon,
InfoIcon,
LinkIcon,
XIcon,
} from 'vue-feather-icons'
export default {
name: 'ToolbarButton',
props: ['source', 'action'],
components: {
SearchIcon,
CloudPlusIcon,
UserPlusIcon,
SortingIcon,
CornerDownRightIcon,
DownloadCloudIcon,
FolderPlusIcon,
@@ -36,48 +60,21 @@
ZoomInIcon,
Trash2Icon,
Edit2Icon,
GridIcon,
ListIcon,
GridIcon,
InfoIcon,
LinkIcon,
XIcon,
} from "vue-feather-icons";
export default {
name: "ToolbarButton",
props: [
'source',
'action'
],
components: {
SearchIcon,
CloudPlusIcon,
UserPlusIcon,
SortingIcon,
CornerDownRightIcon,
DownloadCloudIcon,
FolderPlusIcon,
CloudOffIcon,
PrinterIcon,
ZoomOutIcon,
ZoomInIcon,
Trash2Icon,
Edit2Icon,
ListIcon,
GridIcon,
InfoIcon,
LinkIcon,
XIcon,
},
};
},
}
</script>
<style scoped lang="scss">
@import "resources/sass/vuefilemanager/_variables";
@import "resources/sass/vuefilemanager/_mixins";
@import 'resources/sass/vuefilemanager/_variables';
@import 'resources/sass/vuefilemanager/_mixins';
.preview-sorting {
transform: scale(1.3);
transform: scale(1.3);
}
.button {
@@ -99,7 +96,11 @@
svg {
color: inherit;
path, line, polyline, rect, circle {
path,
line,
polyline,
rect,
circle {
color: inherit;
}
}

View File

@@ -2,16 +2,21 @@
<transition name="info-panel">
<div v-if="fileQueue.length > 0" class="upload-progress">
<div class="progress-title">
<!--Is processing-->
<span v-if="isProcessingFile" class="flex items-center justify-center">
<span v-if="isProcessingFile" class="flex items-center justify-center">
<refresh-cw-icon size="12" class="sync-alt text-theme" />
{{ $t('uploading.processing_file') }}
</span>
<!--Multi file upload-->
<span v-if="!isProcessingFile && fileQueue.length > 0">
{{ $t('uploading.progress', {current:filesInQueueUploaded, total: filesInQueueTotal, progress: uploadingProgress}) }}
<span v-if="!isProcessingFile && fileQueue.length > 0">
{{
$t('uploading.progress', {
current: filesInQueueUploaded,
total: filesInQueueTotal,
progress: uploadingProgress,
})
}}
</span>
</div>
<div class="progress-wrapper">
@@ -25,102 +30,96 @@
</template>
<script>
import ProgressBar from "./ProgressBar";
import { RefreshCwIcon, XIcon } from 'vue-feather-icons'
import {mapGetters} from 'vuex'
import {events} from "../../bus";
import ProgressBar from './ProgressBar'
import { RefreshCwIcon, XIcon } from 'vue-feather-icons'
import { mapGetters } from 'vuex'
import { events } from '../../bus'
export default {
name: 'UploadProgress',
components: {
RefreshCwIcon,
ProgressBar,
XIcon,
export default {
name: 'UploadProgress',
components: {
RefreshCwIcon,
ProgressBar,
XIcon,
},
computed: {
...mapGetters(['filesInQueueUploaded', 'filesInQueueTotal', 'uploadingProgress', 'isProcessingFile', 'fileQueue']),
},
methods: {
cancelUpload() {
events.$emit('cancel-upload')
},
computed: {
...mapGetters([
'filesInQueueUploaded',
'filesInQueueTotal',
'uploadingProgress',
'isProcessingFile',
'fileQueue',
])
},
methods: {
cancelUpload() {
events.$emit('cancel-upload')
}
}
}
},
}
</script>
<style scoped lang="scss">
@import '../../../sass/vuefilemanager/variables';
@import '../../../sass/vuefilemanager/mixins';
@import '../../../sass/vuefilemanager/variables';
@import '../../../sass/vuefilemanager/mixins';
.sync-alt {
animation: spin 1s linear infinite;
margin-right: 5px;
.sync-alt {
animation: spin 1s linear infinite;
margin-right: 5px;
polyline, path {
color: inherit;
}
polyline,
path {
color: inherit;
}
}
@keyframes spin {
0% {
transform: rotate(0);
}
100% {
transform: rotate(360deg);
}
@keyframes spin {
0% {
transform: rotate(0);
}
.info-panel-enter-active,
.info-panel-leave-active {
transition: all 0.3s ease;
100% {
transform: rotate(360deg);
}
}
.info-panel-enter,
.info-panel-leave-to {
opacity: 0;
transform: translateY(-100%);
}
.info-panel-enter-active,
.info-panel-leave-active {
transition: all 0.3s ease;
}
.upload-progress {
width: 100%;
position: relative;
z-index: 1;
.info-panel-enter,
.info-panel-leave-to {
opacity: 0;
transform: translateY(-100%);
}
.progress-wrapper {
display: flex;
.upload-progress {
width: 100%;
position: relative;
z-index: 1;
.cancel-icon {
cursor: pointer;
padding: 0 7px 0 13px;
.progress-wrapper {
display: flex;
&:hover {
.cancel-icon {
cursor: pointer;
padding: 0 7px 0 13px;
line {
color: inherit;
}
&:hover {
line {
color: inherit;
}
}
}
.progress-title {
font-weight: 700;
text-align: center;
span {
@include font-size(14);
}
}
}
.dark {
.progress-bar {
background: $dark_mode_foreground;
.progress-title {
font-weight: 700;
text-align: center;
span {
@include font-size(14);
}
}
}
.dark {
.progress-bar {
background: $dark_mode_foreground;
}
}
</style>