upload request prototype UI

This commit is contained in:
Čarodej
2022-02-16 16:57:57 +01:00
parent 3fafc811fe
commit 394a7b6baf
197 changed files with 6927 additions and 2738 deletions

View File

@@ -68,5 +68,7 @@
"/js/chunks/shared-with-me.js": "/js/chunks/shared-with-me.js",
"/js/chunks/invitation.js": "/js/chunks/invitation.js",
"/css/tailwind.css": "/css/tailwind.css",
"/css/app.css": "/css/app.css"
"/css/app.css": "/css/app.css",
"/js/chunks/request-upload.js": "/js/chunks/request-upload.js",
"/js/chunks/request.js": "/js/chunks/request.js"
}

View File

@@ -20,4 +20,12 @@
.is-inactive {
@apply pointer-events-none opacity-40
}
.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 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;
}

View File

@@ -5,16 +5,16 @@
<ToasterWrapper />
<CookieDisclaimer />
<!--Show spinner before translations is loaded-->
<!--Show spinner before translations is loaded-->
<Spinner v-if="!isLoaded" />
<!--Show warning bar when user functionality is restricted-->
<!--Show warning bar when user functionality is restricted-->
<RestrictionWarningBar />
<!--App view-->
<!--App view-->
<router-view v-if="isLoaded" />
<!--Background under popups-->
<!--Background under popups-->
<Vignette />
</div>
</template>
@@ -26,94 +26,93 @@ import Spinner from './components/FilesView/Spinner'
import Vignette from './components/Others/Vignette'
import Alert from './components/FilesView/Alert'
import RestrictionWarningBar from './components/Subscription/RestrictionWarningBar'
import {mapGetters} from 'vuex'
import {events} from './bus'
import { mapGetters } from 'vuex'
import { events } from './bus'
export default {
name: 'App',
components: {
RestrictionWarningBar,
CookieDisclaimer,
ToasterWrapper,
Vignette,
Spinner,
Alert,
},
data() {
return {
isLoaded: false,
}
},
computed: {
...mapGetters(['config', 'user']),
},
watch: {
'config.defaultThemeMode': function () {
this.handleDarkMode()
},
},
methods: {
spotlightListener(e) {
if (e.key === 'k' && e.metaKey) {
events.$emit('spotlight:show')
}
},
handleDarkMode() {
const app = document.getElementsByTagName('html')[0]
const prefersDarkScheme = window.matchMedia('(prefers-color-scheme: dark)')
name: 'App',
components: {
RestrictionWarningBar,
CookieDisclaimer,
ToasterWrapper,
Vignette,
Spinner,
Alert,
},
data() {
return {
isLoaded: false,
}
},
computed: {
...mapGetters(['config', 'user']),
},
watch: {
'config.defaultThemeMode': function () {
this.handleDarkMode()
},
},
methods: {
spotlightListener(e) {
if (e.key === 'k' && e.metaKey) {
events.$emit('spotlight:show')
}
},
handleDarkMode() {
const app = document.getElementsByTagName('html')[0]
const prefersDarkScheme = window.matchMedia('(prefers-color-scheme: dark)')
if (this.config.defaultThemeMode === 'dark') {
app.classList.add('dark')
this.$store.commit('UPDATE_DARK_MODE_STATUS', true)
} else if (this.config.defaultThemeMode === 'light') {
app.classList.remove('dark')
this.$store.commit('UPDATE_DARK_MODE_STATUS', false)
} else if (this.config.defaultThemeMode === 'system' && prefersDarkScheme.matches) {
app.classList.add('dark')
this.$store.commit('UPDATE_DARK_MODE_STATUS', true)
} else if (this.config.defaultThemeMode === 'system' && !prefersDarkScheme.matches) {
app.classList.remove('dark')
this.$store.commit('UPDATE_DARK_MODE_STATUS', false)
}
},
},
beforeMount() {
window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', () => {
this.handleDarkMode()
})
if (this.config.defaultThemeMode === 'dark') {
app.classList.add('dark')
this.$store.commit('UPDATE_DARK_MODE_STATUS', true)
} else if (this.config.defaultThemeMode === 'light') {
app.classList.remove('dark')
this.$store.commit('UPDATE_DARK_MODE_STATUS', false)
} else if (this.config.defaultThemeMode === 'system' && prefersDarkScheme.matches) {
app.classList.add('dark')
this.$store.commit('UPDATE_DARK_MODE_STATUS', true)
} else if (this.config.defaultThemeMode === 'system' && !prefersDarkScheme.matches) {
app.classList.remove('dark')
this.$store.commit('UPDATE_DARK_MODE_STATUS', false)
}
},
},
beforeMount() {
window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', () => {
this.handleDarkMode()
})
// Commit config
this.$store.commit('INIT', {
config: this.$root.$data.config,
})
// Commit config
this.$store.commit('INIT', {
config: this.$root.$data.config,
})
// Get installation state
let installation = this.$root.$data.config.installation
// Get installation state
let installation = this.$root.$data.config.installation
// Redirect to setup wizard
if (installation === 'installation-needed') {
this.isLoaded = true
// Redirect to setup wizard
if (installation === 'installation-needed') {
this.isLoaded = true
if (window.location.pathname.split('/')[1] !== 'setup-wizard') {
this.$router.push({name: 'StatusCheck'})
}
} else {
this.$store.dispatch('getLanguageTranslations', this.$root.$data.config.locale)
.then(() => {
this.isLoaded = true
})
}
},
created() {
if (this.$isWindows()) {
document.body.classList.add('windows')
}
if (window.location.pathname.split('/')[1] !== 'setup-wizard') {
this.$router.push({ name: 'StatusCheck' })
}
} else {
this.$store.dispatch('getLanguageTranslations', this.$root.$data.config.locale).then(() => {
this.isLoaded = true
})
}
},
created() {
if (this.$isWindows()) {
document.body.classList.add('windows')
}
window.addEventListener('keydown', this.spotlightListener)
},
destroyed() {
window.removeEventListener('keydown', this.spotlightListener)
},
window.addEventListener('keydown', this.spotlightListener)
},
destroyed() {
window.removeEventListener('keydown', this.spotlightListener)
},
}
</script>
@@ -123,54 +122,54 @@ export default {
@import '../sass/vuefilemanager/mixins';
input:-webkit-autofill {
transition-delay: 999999999999s;
transition-delay: 999999999999s;
}
[v-cloak],
[v-cloak] > * {
display: none;
display: none;
}
* {
outline: 0;
margin: 0;
padding: 0;
font-family: 'Nunito', sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
box-sizing: border-box;
-webkit-tap-highlight-color: rgba(0, 0, 0, 0);
font-size: 16px;
text-decoration: none;
color: $text;
outline: 0;
margin: 0;
padding: 0;
font-family: 'Nunito', sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
box-sizing: border-box;
-webkit-tap-highlight-color: rgba(0, 0, 0, 0);
font-size: 16px;
text-decoration: none;
color: $text;
}
.vue-feather {
path,
circle,
line,
rect,
polyline,
ellipse,
polygon {
color: inherit;
}
path,
circle,
line,
rect,
polyline,
ellipse,
polygon {
color: inherit;
}
}
// Dark mode
.dark {
* {
color: $dark_mode_text_primary;
}
* {
color: $dark_mode_text_primary;
}
body,
html {
background: $dark_mode_background;
color: $dark_mode_text_primary;
body,
html {
background: $dark_mode_background;
color: $dark_mode_text_primary;
img {
opacity: 0.95;
}
}
img {
opacity: 0.95;
}
}
}
</style>

View File

@@ -1,5 +1,8 @@
<template>
<div :class="{ 'sm:mb-7 mb-6': !isLast }" class="w-full justify-between space-y-4 sm:flex sm:space-x-8 sm:space-x-2 sm:space-y-0">
<div
:class="{ 'mb-6 sm:mb-7': !isLast }"
class="w-full justify-between space-y-4 sm:flex sm:space-x-8 sm:space-x-2 sm:space-y-0"
>
<!--Label for input-->
<div class="leading-5">
<label class="mb-1.5 block text-sm font-bold text-gray-700 dark:text-gray-200"> {{ title }}: </label>

View File

@@ -1,5 +1,5 @@
<template>
<div :class="{ 'sm:mb-7 mb-6': !isLast }" class="flex w-full items-center justify-between space-x-2 sm:space-x-8">
<div :class="{ 'mb-6 sm:mb-7': !isLast }" class="flex w-full items-center justify-between space-x-2 sm:space-x-8">
<!--Label for input-->
<div class="leading-5">
<label class="mb-1.5 block text-sm font-bold text-gray-700 dark:text-gray-200"> {{ title }}: </label>

View File

@@ -1,7 +1,9 @@
<template>
<div :class="{ 'sm:mb-7 mb-6': !isLast }">
<div :class="{ 'mb-6 sm:mb-7': !isLast }">
<!--Label for input-->
<label v-if="title" class="mb-1.5 block text-sm font-bold text-gray-700 dark:text-gray-200"> {{ title }}: </label>
<label v-if="title" class="mb-1.5 block text-sm font-bold text-gray-700 dark:text-gray-200">
{{ title }}:
</label>
<!--Form element-->
<slot />

View File

@@ -2,7 +2,8 @@
<div id="card-navigation" style="height: 62px" class="mb-7">
<div
:class="{
'fixed top-0 left-0 right-0 z-10 rounded-none bg-white bg-opacity-50 px-6 backdrop-blur-lg backdrop-filter dark:bg-dark-foreground': fixedNav,
'fixed top-0 left-0 right-0 z-10 rounded-none bg-white bg-opacity-50 px-6 backdrop-blur-lg backdrop-filter dark:bg-dark-foreground':
fixedNav,
}"
>
<div class="overflow-x-auto whitespace-nowrap">

View File

@@ -16,7 +16,8 @@
v-if="data.length === 1"
:class="[
{
'rounded-tl-lg rounded-bl-lg border-r-2 border-white dark:border-gray-800': chart.progress < 100,
'rounded-tl-lg rounded-bl-lg border-r-2 border-white dark:border-gray-800':
chart.progress < 100,
'rounded-lg border-none': chart.progress >= 100,
},
chart.color,

View File

@@ -1,8 +1,17 @@
<template>
<DatatableWrapper @init="isLoading = false" api="/api/admin/dashboard/newbies" :paginator="false" :columns="columns" class="mt-6 overflow-x-auto">
<DatatableWrapper
@init="isLoading = false"
api="/api/admin/dashboard/newbies"
:paginator="false"
:columns="columns"
class="mt-6 overflow-x-auto"
>
<template slot-scope="{ row }">
<!--Not a subscription-->
<tr v-if="config.subscriptionType === 'none'" class="whitespace-nowrap border-b border-dashed border-light dark:border-opacity-5">
<tr
v-if="config.subscriptionType === 'none'"
class="whitespace-nowrap border-b border-dashed border-light dark:border-opacity-5"
>
<td class="py-3 pr-3 md:pr-1">
<router-link
:to="{
@@ -13,7 +22,10 @@
<div class="flex items-center">
<MemberAvatar :is-border="false" :size="44" :member="row.data.relationships.settings" />
<div class="ml-3 pr-10">
<b class="max-w-1 block overflow-hidden text-ellipsis whitespace-nowrap text-sm font-bold" style="max-width: 155px">
<b
class="max-w-1 block overflow-hidden text-ellipsis whitespace-nowrap text-sm font-bold"
style="max-width: 155px"
>
{{ row.data.relationships.settings.data.attributes.name }}
</b>
<span class="block text-xs text-gray-600 dark:text-gray-500">
@@ -70,7 +82,10 @@
</tr>
<!--Fixed subscription-->
<tr v-if="config.subscriptionType === 'fixed'" class="whitespace-nowrap border-b border-dashed border-light dark:border-opacity-5">
<tr
v-if="config.subscriptionType === 'fixed'"
class="whitespace-nowrap border-b border-dashed border-light dark:border-opacity-5"
>
<td class="py-3 pr-3 md:pr-1">
<router-link
:to="{
@@ -81,7 +96,10 @@
<div class="flex items-center">
<MemberAvatar :is-border="false" :size="44" :member="row.data.relationships.settings" />
<div class="ml-3 pr-10">
<b class="max-w-1 block overflow-hidden text-ellipsis whitespace-nowrap text-sm font-bold" style="max-width: 155px">
<b
class="max-w-1 block overflow-hidden text-ellipsis whitespace-nowrap text-sm font-bold"
style="max-width: 155px"
>
{{ row.data.relationships.settings.data.attributes.name }}
</b>
<span class="block text-xs text-gray-600 dark:text-gray-500">
@@ -143,7 +161,10 @@
</tr>
<!--Metered subscription-->
<tr v-if="config.subscriptionType === 'metered'" class="whitespace-nowrap border-b border-dashed border-light dark:border-opacity-5">
<tr
v-if="config.subscriptionType === 'metered'"
class="whitespace-nowrap border-b border-dashed border-light dark:border-opacity-5"
>
<td class="py-3 pr-3 md:pr-1">
<router-link
:to="{
@@ -154,7 +175,10 @@
<div class="flex items-center">
<MemberAvatar :is-border="false" :size="44" :member="row.data.relationships.settings" />
<div class="ml-3 pr-10">
<b class="max-w-1 block overflow-hidden text-ellipsis whitespace-nowrap text-sm font-bold" style="max-width: 155px">
<b
class="max-w-1 block overflow-hidden text-ellipsis whitespace-nowrap text-sm font-bold"
style="max-width: 155px"
>
{{ row.data.relationships.settings.data.attributes.name }}
</b>
<span class="block text-xs text-gray-600 dark:text-gray-500">

View File

@@ -11,7 +11,10 @@
<div v-if="row.data.relationships.user" class="flex items-center">
<MemberAvatar :is-border="false" :size="36" :member="row.data.relationships.user" />
<div class="ml-3 pr-10">
<b class="max-w-1 block overflow-hidden text-ellipsis whitespace-nowrap text-sm font-bold" style="max-width: 155px">
<b
class="max-w-1 block overflow-hidden text-ellipsis whitespace-nowrap text-sm font-bold"
style="max-width: 155px"
>
{{ row.data.relationships.user.data.attributes.name }}
</b>
<span class="block text-xs text-gray-600 dark:text-gray-500">
@@ -24,10 +27,16 @@
</span>
</td>
<td class="px-3 md:px-1">
<ColorLabel v-if="config.subscriptionType === 'fixed'" :color="$getTransactionStatusColor(row.data.attributes.status)">
<ColorLabel
v-if="config.subscriptionType === 'fixed'"
:color="$getTransactionStatusColor(row.data.attributes.status)"
>
{{ row.data.attributes.status }}
</ColorLabel>
<ColorLabel v-if="config.subscriptionType === 'metered'" :color="$getTransactionTypeColor(row.data.attributes.type)">
<ColorLabel
v-if="config.subscriptionType === 'metered'"
:color="$getTransactionTypeColor(row.data.attributes.type)"
>
{{ row.data.attributes.type }}
</ColorLabel>
</td>
@@ -43,7 +52,11 @@
</td>
<td class="pl-3 md:pl-1">
<div class="w-32 text-right md:w-full">
<img class="w-32 md:inline-block" :src="$getPaymentLogo(row.data.attributes.driver)" :alt="row.data.attributes.driver" />
<img
class="w-32 md:inline-block"
:src="$getPaymentLogo(row.data.attributes.driver)"
:alt="row.data.attributes.driver"
/>
</div>
</td>
</tr>

View File

@@ -1,5 +1,7 @@
<template>
<button class="group mx-auto inline-block flex items-center whitespace-nowrap rounded-lg border-2 border-black px-7 py-2.5 dark:border-gray-300">
<button
class="group mx-auto inline-block flex items-center whitespace-nowrap rounded-lg border-2 border-black px-7 py-2.5 dark:border-gray-300"
>
<span class="pr-1 text-lg font-extrabold">
{{ text }}
</span>

View File

@@ -1,5 +1,8 @@
<template>
<div v-if="config.allowedFacebookLogin || config.allowedGoogleLogin || config.allowedGithubLogin" class="mb-10 flex items-center justify-center">
<div
v-if="config.allowedFacebookLogin || config.allowedGoogleLogin || config.allowedGithubLogin"
class="mb-10 flex items-center justify-center"
>
<div v-if="config.allowedFacebookLogin" class="mx-5 cursor-pointer">
<facebook-icon @click="socialiteRedirect('facebook')" />
</div>

View File

@@ -1,40 +1,52 @@
<template>
<div v-if="currentFile" class="absolute lg:top-[66px] top-[56px] left-0 right-0 bottom-0 select-none">
<!--Arrow navigation-->
<div v-if="currentFile" class="absolute top-[56px] left-0 right-0 bottom-0 select-none lg:top-[66px]">
<!--Arrow navigation-->
<div v-if="!$isMobile() && files.length > 1" class="">
<div @click.prevent="prev" class="fixed top-1/2 left-0 p-3 cursor-pointer z-20">
<div @click.prevent="prev" class="fixed top-1/2 left-0 z-20 cursor-pointer p-3">
<chevron-left-icon size="20" />
</div>
<div @click.prevent="next" class="fixed top-1/2 right-0 p-3 cursor-pointer z-20">
<div @click.prevent="next" class="fixed top-1/2 right-0 z-20 cursor-pointer p-3">
<chevron-right-icon size="20" />
</div>
</div>
<!--Desktop preview-->
<div v-if="!$isMobile() && (isAudio || isImage || isVideo || isPDF)" class="w-full h-full flex justify-center items-center">
<!--Show PDF-->
<div
v-if="!$isMobile() && (isAudio || isImage || isVideo || isPDF)"
class="flex h-full w-full items-center justify-center"
>
<!--Show PDF-->
<PdfFile v-if="isPDF" :file="currentFile" />
<!--Show Audio, Video and Image-->
<div class="w-full h-full flex items-center justify-center">
<Audio v-if="isAudio" :file="currentFile"/>
<Video v-if="isVideo" :file="currentFile" class="max-w-[1080px] max-h-full self-center mx-auto" />
<ImageFile v-if="isImage" :file="currentFile" class="max-w-[100%] max-h-[100%] self-center mx-auto" />
<div class="flex h-full w-full items-center justify-center">
<Audio v-if="isAudio" :file="currentFile" />
<Video v-if="isVideo" :file="currentFile" class="mx-auto max-h-full max-w-[1080px] self-center" />
<ImageFile v-if="isImage" :file="currentFile" class="mx-auto max-h-[100%] max-w-[100%] self-center" />
</div>
</div>
<!--Mobile Preview-->
<div v-if="$isMobile() && (isAudio || isImage || isVideo || isPDF)" @scroll="checkGroupInView" id="group-box" ref="scrollBox" class="flex gap-6 snap-x snap-mandatory overflow-x-auto h-full">
<div v-for="(file, i) in files" :key="i" :id="`group-${file.data.id}`" class="w-screen h-full flex items-center justify-center snap-center shrink-0 relative">
<ImageFile v-if="isImage" :file="file" class="max-w-[100%] max-h-[100%] self-center mx-auto"/>
<Audio v-if="isAudio" :file="file"/>
<!--Mobile Preview-->
<div
v-if="$isMobile() && (isAudio || isImage || isVideo || isPDF)"
@scroll="checkGroupInView"
id="group-box"
ref="scrollBox"
class="flex h-full snap-x snap-mandatory gap-6 overflow-x-auto"
>
<div
v-for="(file, i) in files"
:key="i"
:id="`group-${file.data.id}`"
class="relative flex h-full w-screen shrink-0 snap-center items-center justify-center"
>
<ImageFile v-if="isImage" :file="file" class="mx-auto max-h-[100%] max-w-[100%] self-center" />
<Audio v-if="isAudio" :file="file" />
<Video v-if="isVideo" :file="file" />
<PdfFile v-if="isPDF" :file="file" />
</div>
</div>
<PdfFile v-if="isPDF" :file="file" />
</div>
</div>
</div>
</template>
@@ -111,29 +123,29 @@ export default {
},
},
methods: {
checkGroupInView: _.debounce(function () {
this.files.forEach((file, index) => {
let element = document.getElementById(`group-${file.data.id}`).getBoundingClientRect()
let scrollBox = document.getElementById('group-box').getBoundingClientRect()
checkGroupInView: _.debounce(function () {
this.files.forEach((file, index) => {
let element = document.getElementById(`group-${file.data.id}`).getBoundingClientRect()
let scrollBox = document.getElementById('group-box').getBoundingClientRect()
// Get video
const video = document.querySelector(`#group-${file.data.id} video`);
// Get video
const video = document.querySelector(`#group-${file.data.id} video`)
// Pause video when playing
if (video && !video.paused) {
video.pause()
}
// Pause video when playing
if (video && !video.paused) {
video.pause()
}
// Check if the group is in the viewport of group-box
if (element.left === scrollBox.left) {
this.currentIndex = index
}
})
}, 100),
// Check if the group is in the viewport of group-box
if (element.left === scrollBox.left) {
this.currentIndex = index
}
})
}, 100),
getFilesForView() {
let requestedFile = this.clipboard[0]
this.entries.map(element => {
this.entries.map((element) => {
if (requestedFile.data.attributes.mimetype === 'pdf') {
if (element.data.attributes.mimetype === 'pdf') this.files.push(element)
} else {
@@ -143,18 +155,18 @@ export default {
this.files.forEach((element, index) => {
if (element.data.id === this.clipboard[0].data.id) {
this.currentIndex = index
this.currentIndex = index
}
})
// Scroll to the selected item
if (this.$isMobile()) {
this.$nextTick(() => {
let element = document.getElementById(`group-${this.files[this.currentIndex].data.id}`)
// Scroll to the selected item
if (this.$isMobile()) {
this.$nextTick(() => {
let element = document.getElementById(`group-${this.files[this.currentIndex].data.id}`)
this.$refs.scrollBox.scrollLeft = element.getBoundingClientRect().left
})
}
this.$refs.scrollBox.scrollLeft = element.getBoundingClientRect().left
})
}
},
next() {
if (!this.files.length > 1) return

View File

@@ -1,5 +1,5 @@
<template>
<div v-if="currentFile" class="items-center px-3.5 py-4 lg:grid lg:grid-cols-3 lg:py-3 select-none">
<div v-if="currentFile" class="select-none items-center px-3.5 py-4 lg:grid lg:grid-cols-3 lg:py-3">
<div class="flex items-center justify-between lg:w-auto lg:justify-start">
<!--Close icon-->
<div @click="closeFullPreview" class="order-last -m-3 cursor-pointer p-3 lg:order-none">

View File

@@ -1,5 +1,10 @@
<template>
<audio :class="{ 'file-shadow': !$isMobile() }" class="file audio" :src="file.data.attributes.file_url" controls></audio>
<audio
:class="{ 'file-shadow': !$isMobile() }"
class="file audio"
:src="file.data.attributes.file_url"
controls
></audio>
</template>
<script>

View File

@@ -31,9 +31,7 @@ export default {
components: {
pdf,
},
props: [
'file',
],
props: ['file'],
watch: {
file() {
this.getPdf()

View File

@@ -1,13 +1,13 @@
<template>
<video
:src="file.data.attributes.file_url"
class="video"
:class="{ 'file-shadow': !$isMobile() }"
controlsList="nodownload"
disablePictureInPicture
playsinline
controls
/>
<video
:src="file.data.attributes.file_url"
class="video"
:class="{ 'file-shadow': !$isMobile() }"
controlsList="nodownload"
disablePictureInPicture
playsinline
controls
/>
</template>
<script>

View File

@@ -10,7 +10,9 @@
<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>

View File

@@ -31,13 +31,12 @@
<!--File Controls-->
<div class="ml-5 flex items-center xl:ml-8">
<!--Action buttons-->
<div v-if="canEdit && !$isMobile()" class="flex items-center">
<ToolbarButton
@click.native="$moveFileOrFolder(clipboard[0])"
:class="{
'is-inactive': ! canManipulate,
'is-inactive': !canManipulate,
}"
source="move"
:action="$t('actions.move')"
@@ -45,7 +44,7 @@
<ToolbarButton
@click.native="$deleteFileOrFolder(clipboard[0])"
:class="{
'is-inactive': ! canManipulate,
'is-inactive': !canManipulate,
}"
source="trash"
:action="$t('actions.delete')"
@@ -107,19 +106,13 @@ export default {
Option,
},
computed: {
...mapGetters([
'isVisibleNavigationBars',
'currentTeamFolder',
'currentFolder',
'sharedDetail',
'clipboard',
]),
...mapGetters(['isVisibleNavigationBars', 'currentTeamFolder', 'currentFolder', 'sharedDetail', 'clipboard']),
canEdit() {
return this.sharedDetail && this.sharedDetail.data.attributes.permission === 'editor'
},
canManipulate() {
return this.clipboard[0]
}
canManipulate() {
return this.clipboard[0]
},
},
methods: {
showCreateMenu() {

View File

@@ -12,20 +12,27 @@
:action="$t('actions.create')"
/>
<PopoverItem name="desktop-create" side="left">
<OptionGroup :title="$t('Upload')" :class="{'is-inactive': canUploadInView || isTeamFolderHomepage || isSharedWithMeHomepage}">
<OptionGroup
:title="$t('Upload')"
:class="{
'is-inactive': canUploadInView || isTeamFolderHomepage || isSharedWithMeHomepage,
}"
>
<OptionUpload :title="$t('actions.upload')" type="file" />
<OptionUpload :title="$t('actions.upload_folder')" type="folder" />
</OptionGroup>
<OptionGroup :title="$t('Create')">
<Option
@click.stop.native="$createFolder"
:class="{ 'is-inactive': canCreateFolder || isTeamFolderHomepage || isSharedWithMeHomepage }"
:class="{
'is-inactive': canCreateFolder || isTeamFolderHomepage || isSharedWithMeHomepage,
}"
:title="$t('actions.create_folder')"
icon="folder-plus"
/>
<Option
@click.stop.native="$createTeamFolder"
:class="{ 'is-inactive': canCreateTeamFolder || isSharedWithMeHomepage }"
:class="{ 'is-inactive': canCreateTeamFolder || isSharedWithMeHomepage }"
:title="$t('Create Team Folder')"
icon="users"
/>

View File

@@ -0,0 +1,147 @@
<template>
<div class="hidden lg:block">
<div class="flex items-center justify-between py-3">
<NavigationBar />
<div class="flex items-center">
<div class="bg-theme-200 mr-6 flex cursor-pointer items-center rounded-lg py-1 pr-1 pl-4">
<b @click="uploadingDone" class="text-theme mr-3 text-xs">
{{ isDone ? $t('Awesome!') : $t('Tell Jane you are done!') }}
</b>
<img
class="w-8 rounded-lg"
src="http://192.168.1.112:8000/avatars/md-f45abbe5-962c-4229-aef2-9991e96d54d9.png"
alt="Avatar"
/>
</div>
<!--Create button-->
<PopoverWrapper>
<ToolbarButton
@click.stop.native="showCreateMenu"
source="cloud-plus"
:action="$t('actions.create')"
/>
<PopoverItem name="desktop-create" side="left">
<OptionGroup :title="$t('Upload')">
<OptionUpload :title="$t('actions.upload')" type="file" />
<OptionUpload :title="$t('actions.upload_folder')" type="folder" />
</OptionGroup>
<OptionGroup :title="$t('Create')">
<Option
@click.stop.native="$createFolder"
:title="$t('actions.create_folder')"
icon="folder-plus"
/>
</OptionGroup>
</PopoverItem>
</PopoverWrapper>
<!--File Controls-->
<div v-if="!$isMobile()" class="ml-5 flex items-center xl:ml-8">
<ToolbarButton
@click.native="$moveFileOrFolder(clipboard[0])"
:class="{
'is-inactive': !canManipulate,
}"
source="move"
:action="$t('actions.move')"
/>
<ToolbarButton
@click.native="$deleteFileOrFolder(clipboard[0])"
:class="{
'is-inactive': !canManipulate,
}"
source="trash"
:action="$t('actions.delete')"
/>
</div>
<!--View Controls-->
<div class="ml-5 flex items-center xl:ml-8">
<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"
/>
</div>
</div>
</div>
<UploadProgress />
</div>
</template>
<script>
import PopoverWrapper from '../Desktop/PopoverWrapper'
import FileSortingOptions from './FileSortingOptions'
import PopoverItem from '../Desktop/PopoverItem'
import UploadProgress from './UploadProgress'
import NavigationBar from './NavigationBar'
import ToolbarButton from './ToolbarButton'
import OptionUpload from './OptionUpload'
import OptionGroup from './OptionGroup'
import SearchBar from './SearchBar'
import { events } from '../../bus'
import { mapGetters } from 'vuex'
import Option from './Option'
export default {
name: 'DesktopUploadRequestToolbar',
components: {
FileSortingOptions,
UploadProgress,
PopoverWrapper,
NavigationBar,
ToolbarButton,
OptionUpload,
OptionGroup,
PopoverItem,
SearchBar,
Option,
},
computed: {
...mapGetters(['isVisibleNavigationBars', 'currentTeamFolder', 'currentFolder', 'sharedDetail', 'clipboard']),
canEdit() {
return this.sharedDetail && this.sharedDetail.data.attributes.permission === 'editor'
},
canManipulate() {
return this.clipboard[0]
},
},
data() {
return {
isDone: false,
}
},
methods: {
uploadingDone() {
// TODO: add name to the message
if (!this.isDone) {
events.$emit('toaster', {
type: 'success',
message: this.$t('We notified Jane about your new uploads successfully.'),
})
}
this.isDone = true
},
showCreateMenu() {
events.$emit('popover:open', 'desktop-create')
},
showSortingMenu() {
events.$emit('popover:open', 'desktop-sorting')
},
},
}
</script>

View File

@@ -1,7 +1,11 @@
<template>
<div v-show="isVisible" id="drag-ui" class="w-64 fixed z-20 pointer-events-none p-5 rounded-xl shadow-lg dark:bg-dark-foreground bg-white">
<TitlePreview icon="check-square" :title="title" :subtitle="subtitle" />
</div>
<div
v-show="isVisible"
id="drag-ui"
class="pointer-events-none fixed z-20 w-64 rounded-xl bg-white p-5 shadow-lg dark:bg-dark-foreground"
>
<TitlePreview icon="check-square" :title="title" :subtitle="subtitle" />
</div>
</template>
<script>
@@ -42,7 +46,9 @@ 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)
return this.draggedItem.items == 0
? this.$t('folder.empty')
: this.$tc('folder.item_counts', this.draggedItem.items)
}
// Subtitle for single file

View File

@@ -1,7 +1,9 @@
<template>
<div class="sticky top-14 z-[19] block overflow-x-auto whitespace-nowrap bg-white px-4 pb-3 dark:bg-dark-background lg:hidden">
<div
class="sticky top-14 z-[19] block overflow-x-auto whitespace-nowrap bg-white px-4 pb-3 dark:bg-dark-background lg:hidden"
>
<!--Show Buttons-->
<slot v-if="!isMultiSelectMode" />
<slot v-if="!isMultiSelectMode" />
<!-- Multi select mode -->
<div v-if="isMultiSelectMode">

View File

@@ -109,7 +109,7 @@ export default {
})
}
} else {
console.log(data.data.type);
console.log(data.data.type)
// Get id from current folder
const id = data.data.type !== 'folder' ? this.currentFolder?.data.id : data.data.id
@@ -144,13 +144,3 @@ export default {
},
}
</script>
<style>
.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 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

@@ -2,13 +2,43 @@
<MenuMobile name="file-filter">
<MenuMobileGroup>
<OptionGroup :title="$t('Base')">
<Option @click.native="goToFiles" :title="$t('sidebar.home')" icon="hard-drive" :is-active="$isThisRoute($route, 'Files')" :is-hover-disabled="true" />
<Option @click.native="goToLatest" :title="$t('menu.latest')" icon="upload-cloud" :is-active="$isThisRoute($route, 'RecentUploads')" :is-hover-disabled="true" />
<Option @click.native="goToShared" :title="$t('sidebar.my_shared')" icon="share" :is-active="$isThisRoute($route, 'MySharedItems')" :is-hover-disabled="true" />
<Option @click.native="goToTrash" :title="$t('menu.trash')" icon="trash" :is-active="$isThisRoute($route, 'Trash')" :is-hover-disabled="true" />
<Option
@click.native="goToFiles"
:title="$t('sidebar.home')"
icon="hard-drive"
:is-active="$isThisRoute($route, 'Files')"
:is-hover-disabled="true"
/>
<Option
@click.native="goToLatest"
:title="$t('menu.latest')"
icon="upload-cloud"
:is-active="$isThisRoute($route, 'RecentUploads')"
:is-hover-disabled="true"
/>
<Option
@click.native="goToShared"
:title="$t('sidebar.my_shared')"
icon="share"
:is-active="$isThisRoute($route, 'MySharedItems')"
:is-hover-disabled="true"
/>
<Option
@click.native="goToTrash"
:title="$t('menu.trash')"
icon="trash"
:is-active="$isThisRoute($route, 'Trash')"
:is-hover-disabled="true"
/>
</OptionGroup>
<OptionGroup :title="$t('Collaboration')">
<Option @click.native="goToTeamFolders" :title="$t('Team Folders')" icon="users" :is-active="$isThisRoute($route, 'TeamFolders')" :is-hover-disabled="true" />
<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')"

View File

@@ -1,10 +1,19 @@
<template>
<div class="flex items-center justify-center">
<span class="text-theme absolute z-10 mx-auto mt-1 inline-block w-7 overflow-hidden text-ellipsis text-center font-semibold text-[9px]">
<span
class="text-theme absolute z-10 mx-auto mt-1 inline-block w-7 overflow-hidden text-ellipsis text-center text-[9px] font-semibold"
>
{{ 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">
<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"

View File

@@ -1,12 +1,32 @@
<template>
<div>
<OptionGroup :title="$t('View')">
<Option v-if="isList" @click.native="changePreview('grid')" :title="$t('preview_sorting.grid_view')" icon="grid" />
<Option v-if="isGrid" @click.native="changePreview('list')" :title="$t('preview_sorting.list_view')" icon="list" />
<Option
v-if="isList"
@click.native="changePreview('grid')"
:title="$t('preview_sorting.grid_view')"
icon="grid"
/>
<Option
v-if="isGrid"
@click.native="changePreview('list')"
:title="$t('preview_sorting.list_view')"
icon="list"
/>
</OptionGroup>
<OptionGroup :title="$t('Sorting')">
<Option @click.native.stop="sort('created_at')" :arrow="arrowForCreatedAtField" :title="$t('preview_sorting.sort_date')" icon="calendar" />
<Option @click.native.stop="sort('name')" :arrow="arrowForNameField" :title="$t('preview_sorting.sort_alphabet')" icon="alphabet" />
<Option
@click.native.stop="sort('created_at')"
:arrow="arrowForCreatedAtField"
:title="$t('preview_sorting.sort_date')"
icon="calendar"
/>
<Option
@click.native.stop="sort('name')"
:arrow="arrowForNameField"
:title="$t('preview_sorting.sort_alphabet')"
icon="alphabet"
/>
</OptionGroup>
</div>
</template>

View File

@@ -14,7 +14,10 @@
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>
<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>
</template>

View File

@@ -1,5 +1,12 @@
<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">
<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"

View File

@@ -1,5 +1,10 @@
<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">
<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
@@ -35,7 +40,9 @@
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="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>

View File

@@ -1,5 +1,7 @@
<template>
<div class="hidden 2xl:w-[360px] xl:w-[320px] w-[300px] shrink-0 overflow-y-auto overflow-x-hidden px-2.5 pt-2 lg:block">
<div
class="hidden w-[300px] shrink-0 overflow-y-auto overflow-x-hidden px-2.5 pt-2 lg:block xl:w-[320px] 2xl:w-[360px]"
>
<!--Is empty clipboard-->
<div v-if="isEmpty" class="flex h-full items-center justify-center">
<div class="text-center">
@@ -23,10 +25,19 @@
<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" />
<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" />
@@ -35,14 +46,21 @@
<ListInfoItem v-if="$checkPermission(['master'])" :title="$t('file_detail.where')">
<div @click="$moveFileOrFolder(singleFile)" class="flex cursor-pointer items-center">
<b class="inline-block text-sm font-bold">
{{ singleFile.data.relationships.parent ? singleFile.data.relationships.parent.data.attributes.name : $getCurrentLocationName() }}
{{
singleFile.data.relationships.parent
? singleFile.data.relationships.parent.data.attributes.name
: $getCurrentLocationName()
}}
</b>
<Edit2Icon size="10" class="ml-2" />
</div>
</ListInfoItem>
<!--Shared-->
<ListInfoItem v-if="$checkPermission('master') && singleFile.data.relationships.shared" :title="$t('file_detail.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 }}
@@ -50,8 +68,18 @@
<Edit2Icon size="10" class="ml-2" />
</div>
<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" />
<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>
@@ -60,7 +88,7 @@
<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="text-sm ml-3 block font-bold">
<span class="ml-3 block text-sm font-bold">
{{ singleFile.data.relationships.owner.data.attributes.name }}
</span>
</div>
@@ -112,7 +140,9 @@ export default {
return this.clipboard[0]
},
canShowMetaData() {
return this.clipboard[0].data.attributes.metadata && this.clipboard[0].data.attributes.metadata.ExifImageWidth
return (
this.clipboard[0].data.attributes.metadata && this.clipboard[0].data.attributes.metadata.ExifImageWidth
)
},
isLocked() {
return this.clipboard[0].data.relationships.shared.protected

View File

@@ -96,13 +96,17 @@
<!--File & Image sub line-->
<small v-if="!isFolder" class="block text-xs text-gray-500 dark:text-gray-500">
{{ entry.data.attributes.filesize }}
<span class="hidden text-xs text-gray-500 dark:text-gray-500 lg:inline-block">, {{ timeStamp }}</span>
<span class="hidden text-xs text-gray-500 dark:text-gray-500 lg:inline-block"
>, {{ timeStamp }}</span
>
</small>
<!--Folder sub line-->
<small v-if="isFolder" class="block text-xs text-gray-500 dark:text-gray-500">
{{ folderItems === 0 ? $t('folder.empty') : $tc('folder.item_counts', folderItems)
}}<span class="hidden text-xs text-gray-500 dark:text-gray-500 lg:inline-block">, {{ timeStamp }}</span>
}}<span class="hidden text-xs text-gray-500 dark:text-gray-500 lg:inline-block"
>, {{ timeStamp }}</span
>
</small>
</div>
</div>

View File

@@ -18,7 +18,7 @@
:entry="item"
:highlight="true"
:mobile-handler="true"
:can-hover="true"
:can-hover="true"
@mouseup.stop.native="clickFilter"
@dragstart.native="$emit('dragstart')"
@drop.native="drop()"
@@ -184,7 +184,10 @@ export default {
events.$emit('file-preview:show')
} 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)
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)
}

View File

@@ -14,16 +14,30 @@
<!--Item thumbnail-->
<div class="relative w-16 shrink-0">
<!--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" />
<MemberAvatar
v-if="user && canShowAuthor"
:size="28"
:is-border="true"
:member="entry.data.relationships.owner"
class="absolute right-1.5 -bottom-2 z-10"
/>
<!--Emoji Icon-->
<Emoji v-if="entry.data.attributes.emoji" :emoji="entry.data.attributes.emoji" class="ml-1 scale-110 transform text-5xl" />
<Emoji
v-if="entry.data.attributes.emoji"
:emoji="entry.data.attributes.emoji"
class="ml-1 scale-110 transform text-5xl"
/>
<!--Folder Icon-->
<FolderIcon v-if="isFolder && !entry.data.attributes.emoji" :item="entry" />
<!--File Icon-->
<FileIconThumbnail v-if="isFile || isVideo || isAudio || (isImage && !entry.data.attributes.thumbnail)" :entry="entry" class="pr-2" />
<FileIconThumbnail
v-if="isFile || isVideo || isAudio || (isImage && !entry.data.attributes.thumbnail)"
:entry="entry"
class="pr-2"
/>
<!--Image thumbnail-->
<img
@@ -40,7 +54,7 @@
<!--Item Title-->
<b
class="mb-0.5 block overflow-hidden text-ellipsis whitespace-nowrap text-sm"
:class="{'hover:underline': canEditName}"
:class="{ 'hover:underline': canEditName }"
style="max-width: 240px"
ref="name"
@input="renameItem"
@@ -60,19 +74,23 @@
<!--File & Image sub line-->
<small v-if="!isFolder" class="block text-xs text-gray-500 dark:text-gray-500">
{{ entry.data.attributes.filesize }}, {{ timeStamp }}
</small>
{{ entry.data.attributes.filesize }}, {{ timeStamp }}
</small>
<!--Folder sub line-->
<small v-if="isFolder" class="block text-xs text-gray-500 dark:text-gray-500">
{{ folderItems === 0 ? $t('folder.empty') : $tc('folder.item_counts', folderItems) }}, {{ timeStamp }}
{{ 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="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">
<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">
@@ -149,7 +167,9 @@ export default {
)
},
folderItems() {
return this.entry.data.attributes.deleted_at ? this.entry.data.attributes.trashed_items : this.entry.data.attributes.items
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
@@ -182,14 +202,14 @@ export default {
this.itemName = this.entry.data.attributes.name
// Change item name
events.$on('change:name', item => {
events.$on('change:name', (item) => {
if (this.entry.data.id === item.id) {
this.itemName = item.name
}
this.itemName = item.name
}
})
// Autofocus after newly created folder
events.$on('newFolder:focus', id => {
events.$on('newFolder:focus', (id) => {
if (!this.$isMobile() && this.entry.data.id === id) {
this.$refs.name.focus()
document.execCommand('selectAll')

View File

@@ -39,7 +39,9 @@ export default {
props: ['isBorder', 'member', 'size'],
computed: {
letter() {
let string = this.member.data.attributes.name ? this.member.data.attributes.name : this.member.data.attributes.email
let string = this.member.data.attributes.name
? this.member.data.attributes.name
: this.member.data.attributes.email
return string.substr(0, 1)
},

View File

@@ -5,7 +5,12 @@
<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')" />
<ToolbarButton
@click.native="closeSelecting"
class="action-btn close-icon"
source="close"
:action="$t('actions.close')"
/>
</div>
</transition>
</template>

View File

@@ -1,8 +1,11 @@
<template>
<div @click="goBack" class="flex items-center text-left select-none relative">
<!--Menu icon-->
<div v-if="!isVisibleNavigationBars" @click="toggleNavigationBars" class="-mt-0.5 mr-2 p-2 cursor-pointer lg:block hidden">
<div @click="goBack" class="relative flex select-none items-center text-left">
<!--Menu icon-->
<div
v-if="!isVisibleNavigationBars"
@click="toggleNavigationBars"
class="-mt-0.5 mr-2 hidden cursor-pointer p-2 lg:block"
>
<menu-icon size="17" />
</div>
@@ -12,13 +15,13 @@
'-translate-x-3 opacity-0': !isLoadedFolder || !isNotHomepage,
'translate-x-0 opacity-100': isLoadedFolder && isNotHomepage,
}"
class="lg:-mt-0.5 mr-2 -ml-1 cursor-pointer align-middle transition-all duration-200"
class="mr-2 -ml-1 cursor-pointer align-middle transition-all duration-200 lg:-mt-0.5"
/>
<!--Folder Title-->
<b
:class="{ '-translate-x-4': !isLoadedFolder || !isNotHomepage }"
class="inline-block transform overflow-hidden text-ellipsis whitespace-nowrap align-middle text-sm font-bold transition-all duration-200 max-w-[200px]"
class="inline-block max-w-[200px] transform overflow-hidden text-ellipsis whitespace-nowrap align-middle text-sm font-bold transition-all duration-200"
>
{{ $getCurrentLocationName() }}
</b>
@@ -29,60 +32,56 @@
'-translate-x-4 opacity-0': !currentFolder || !isNotHomepage,
'translate-x-0 opacity-100': currentFolder && isNotHomepage,
}"
class="relative ml-3 transform rounded-md bg-light-background py-0.5 px-1.5 transition-all duration-200 dark:bg-dark-foreground cursor-pointer"
id="folder-actions"
class="relative ml-3 transform cursor-pointer rounded-md bg-light-background py-0.5 px-1.5 transition-all duration-200 dark:bg-dark-foreground"
id="folder-actions"
>
<more-horizontal-icon size="14" />
</div>
</div>
</template>
<script>
import {mapGetters} from "vuex";
import {events} from "../../bus";
import { mapGetters } from 'vuex'
import { events } from '../../bus'
import { MenuIcon, ChevronLeftIcon, MoreHorizontalIcon } from 'vue-feather-icons'
export default {
name: 'NavigationBar',
components: {
MoreHorizontalIcon,
ChevronLeftIcon,
MenuIcon,
},
computed: {
...mapGetters([
'isVisibleNavigationBars',
'currentFolder',
'sharedDetail',
]),
isNotHomepage() {
if (this.$isThisRoute(this.$route, ['Public'])) {
return this.sharedDetail && this.sharedDetail.data.attributes.item_id !== this.$route.params.id
}
components: {
MoreHorizontalIcon,
ChevronLeftIcon,
MenuIcon,
},
computed: {
...mapGetters(['isVisibleNavigationBars', 'currentFolder', 'sharedDetail']),
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
},
isLoadedFolder() {
return this.$route.params.id
},
},
methods: {
goBack() {
if (this.isNotHomepage) this.$router.back()
},
showItemActions() {
if (window.innerWidth > 1024) {
events.$emit('context-menu:current-folder', this.currentFolder)
} else {
this.$store.commit('CLIPBOARD_CLEAR')
this.$store.commit('ADD_ITEM_TO_CLIPBOARD', this.currentFolder)
return this.$route.params.id
},
isLoadedFolder() {
return this.$route.params.id
},
},
methods: {
goBack() {
if (this.isNotHomepage) this.$router.back()
},
showItemActions() {
if (window.innerWidth > 1024) {
events.$emit('context-menu:current-folder', this.currentFolder)
} else {
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)
}
},
toggleNavigationBars() {
this.$store.dispatch('toggleNavigationBars')
},
}
this.$showMobileMenu('file-menu')
events.$emit('mobile-context-menu:show', this.currentFolder)
}
},
toggleNavigationBars() {
this.$store.dispatch('toggleNavigationBars')
},
},
}
</script>

View File

@@ -1,54 +1,244 @@
<template>
<li
class="flex items-center justify-between py-4 px-5"
:class="{'group cursor-pointer hover:bg-light-background dark:hover:bg-4x-dark-foreground': !isHoverDisabled}"
class="flex items-center justify-between py-3.5 px-5"
: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 }" />
<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>

View File

@@ -1,19 +1,17 @@
<template>
<div>
<b v-if="title" class="py-0.5 px-4 mt-2 block text-xs text-gray-400 dark-text-theme">
{{ title }}
</b>
<ul class="option-group py-1">
<slot></slot>
</ul>
</div>
<div>
<b v-if="title" class="dark-text-theme mt-2 block py-0.5 px-4 text-xs text-gray-400">
{{ title }}
</b>
<ul class="option-group py-1">
<slot></slot>
</ul>
</div>
</template>
<script>
export default {
name: 'OptionGroup',
props: [
'title'
]
props: ['title'],
}
</script>

View File

@@ -1,16 +1,33 @@
<template>
<label
class="flex items-center py-4 px-5 group cursor-pointer hover:bg-light-background dark:hover:bg-4x-dark-foreground"
>
class="group flex cursor-pointer items-center py-4 px-5 hover:bg-light-background dark:hover:bg-4x-dark-foreground"
>
<div class="mr-4">
<upload-cloud-icon v-if="type === 'file'" size="17" class="vue-feather group-hover-text-theme" />
<folder-upload-icon v-if="type === 'folder'" size="17" class="vue-feather group-hover-text-theme" />
</div>
<div class="group-hover-text-theme text-sm font-bold text-left">
<div class="group-hover-text-theme text-left text-sm font-bold">
{{ title }}
<input v-if="type === 'file'" @change="emmitFiles" v-show="false" id="file" type="file" name="files[]" multiple />
<input v-if="type === 'folder'" @change="emmitFolder" v-show="false" id="folder" type="file" name="folders[]" webkitdirectory mozdirectory />
<input
v-if="type === 'file'"
@change="emmitFiles"
v-show="false"
id="file"
type="file"
name="files[]"
multiple
/>
<input
v-if="type === 'folder'"
@change="emmitFolder"
v-show="false"
id="folder"
type="file"
name="folders[]"
webkitdirectory
mozdirectory
/>
</div>
</label>
</template>
@@ -30,8 +47,8 @@ export default {
emmitFiles(e) {
this.$uploadFiles(e.target.files)
},
emmitFolder(e) {
this.$store.commit('UPDATE_UPLOADING_FOLDER_STATE', true)
emmitFolder(e) {
this.$store.commit('UPDATE_UPLOADING_FOLDER_STATE', true)
this.$uploadFiles(e.target.files)
},

View File

@@ -1,5 +1,8 @@
<template>
<div @click="$openSpotlight()" class="relative cursor-pointer rounded-lg bg-light-background dark:bg-dark-foreground">
<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-4 py-2.5 text-left xl:w-64">
<div class="flex items-center">
<search-icon size="18" class="vue-feather text-gray-400 dark:text-gray-600" />
@@ -7,7 +10,9 @@
{{ $t('inputs.placeholder_search_files') }}
</span>
</div>
<span class="rounded dark:border-slate-200 border px-1 py-0.5 text-xs font-bold tracking-normal text-gray-400 dark:border-opacity-5 dark:text-gray-600">
<span
class="rounded border px-1 py-0.5 text-xs font-bold tracking-normal text-gray-400 dark:border-slate-200 dark:border-opacity-5 dark:text-gray-600"
>
{{ metaKeyIcon }}+K
</span>
</div>

View File

@@ -1,5 +1,8 @@
<template>
<button class="group h-[42px] w-[42px] inline-flex items-center justify-center cursor-pointer rounded-lg dark:hover:bg-2x-dark-foreground hover:bg-light-background" :title="action">
<button
class="group inline-flex h-[42px] w-[42px] cursor-pointer items-center justify-center rounded-lg hover:bg-light-background dark:hover:bg-2x-dark-foreground"
:title="action"
>
<corner-down-right-icon v-if="source === 'move'" size="19" class="vue-feather group-hover-text-theme" />
<download-cloud-icon v-if="source === 'download'" size="19" class="vue-feather group-hover-text-theme" />
<folder-plus-icon v-if="source === 'folder-plus'" size="19" class="vue-feather group-hover-text-theme" />
@@ -10,14 +13,19 @@
<printer-icon v-if="source === 'print'" size="19" class="vue-feather group-hover-text-theme" />
<trash-2-icon v-if="source === 'trash'" size="19" class="vue-feather group-hover-text-theme" />
<list-icon v-if="source === 'th-list'" size="19" class="vue-feather group-hover-text-theme" />
<info-icon v-if="source === 'info'" size="19" class="vue-feather group-hover-text-theme" :class="{'text-theme': isVisibleSidebar}" />
<info-icon
v-if="source === 'info'"
size="19"
class="vue-feather group-hover-text-theme"
:class="{ 'text-theme': isVisibleSidebar }"
/>
<grid-icon v-if="source === 'th'" size="19" class="vue-feather group-hover-text-theme" />
<link-icon v-if="source === 'share'" size="19" class="vue-feather group-hover-text-theme" />
<x-icon v-if="source === 'close'" size="19" class="vue-feather group-hover-text-theme" />
<search-icon v-if="source === 'search'" size="19" class="vue-feather group-hover-text-theme" />
<cloud-off-icon v-if="source === 'shared-off'" size="19" class="vue-feather group-hover-text-theme" />
<sorting-icon v-if="source === 'preview-sorting'" class="scale-125 vue-feather group-hover-text-theme" />
<CloudPlusIcon v-if="source === 'cloud-plus'" class="scale-125 vue-feather group-hover-text-theme" />
<sorting-icon v-if="source === 'preview-sorting'" class="vue-feather group-hover-text-theme scale-125" />
<CloudPlusIcon v-if="source === 'cloud-plus'" class="vue-feather group-hover-text-theme scale-125" />
</button>
</template>
@@ -42,16 +50,14 @@ import {
LinkIcon,
XIcon,
} from 'vue-feather-icons'
import {mapGetters} from "vuex";
import { mapGetters } from 'vuex'
export default {
name: 'ToolbarButton',
props: ['source', 'action'],
computed: {
...mapGetters([
'isVisibleSidebar'
])
},
computed: {
...mapGetters(['isVisibleSidebar']),
},
components: {
SearchIcon,
CloudPlusIcon,
@@ -73,4 +79,4 @@ export default {
XIcon,
},
}
</script>
</script>

View File

@@ -43,7 +43,13 @@ export default {
XIcon,
},
computed: {
...mapGetters(['filesInQueueUploaded', 'filesInQueueTotal', 'uploadingProgress', 'isProcessingFile', 'fileQueue']),
...mapGetters([
'filesInQueueUploaded',
'filesInQueueTotal',
'uploadingProgress',
'isProcessingFile',
'fileQueue',
]),
},
methods: {
cancelUpload() {

View File

@@ -18,7 +18,9 @@
<footer class="plan-footer">
<b class="price text-theme">
{{ plan.data.attributes.price }}/{{ $t('global.monthly_ac') }}
<small v-if="plan.data.attributes.tax_rates.length > 0" class="vat-disclaimer">{{ $t('page_pricing_tables.vat_excluded') }}</small>
<small v-if="plan.data.attributes.tax_rates.length > 0" class="vat-disclaimer">{{
$t('page_pricing_tables.vat_excluded')
}}</small>
</b>
</footer>
</div>

View File

@@ -1,8 +1,17 @@
<template>
<div class="page-wrapper large get-started" v-if="index.section_get_started === '1'">
<PageTitle class="page-title" type="center" :title="index.get_started_title" :description="index.get_started_description"></PageTitle>
<PageTitle
class="page-title"
type="center"
:title="index.get_started_title"
:description="index.get_started_description"
></PageTitle>
<router-link tag="button" class="get-started-button bg-theme-800 hover-bg-theme shadow-theme" :to="{ name: 'SignUp' }">
<router-link
tag="button"
class="get-started-button bg-theme-800 hover-bg-theme shadow-theme"
:to="{ name: 'SignUp' }"
>
<span class="content">{{ $t('page_index.get_started_button') }}</span>
<chevron-right-icon size="22"></chevron-right-icon>
</router-link>

View File

@@ -23,7 +23,18 @@
<script>
import { mapGetters } from 'vuex'
import { FolderPlusIcon, HardDriveIcon, SettingsIcon, Trash2Icon, SearchIcon, ImageIcon, GridIcon, LinkIcon, StarIcon, EyeIcon } from 'vue-feather-icons'
import {
FolderPlusIcon,
HardDriveIcon,
SettingsIcon,
Trash2Icon,
SearchIcon,
ImageIcon,
GridIcon,
LinkIcon,
StarIcon,
EyeIcon,
} from 'vue-feather-icons'
export default {
name: 'IndexHeroScreenshot',

View File

@@ -1,6 +1,11 @@
<template>
<section class="main-features page-wrapper medium">
<PageTitle v-if="index.section_features === '1'" type="center" :title="index.features_title" :description="index.features_description"></PageTitle>
<PageTitle
v-if="index.section_features === '1'"
type="center"
:title="index.features_title"
:description="index.features_description"
></PageTitle>
<div v-if="index.section_feature_boxes === '1'" class="content">
<div class="hero">
<img src="/assets/images/hero-Illustration.svg" alt="Hero" />

View File

@@ -1,7 +1,11 @@
<template>
<nav class="main-navigation">
<router-link :to="{ name: 'Homepage' }" tag="div" class="logo">
<img v-if="config.app_logo_horizontal" :src="$getImage(config.app_logo_horizontal)" :alt="config.app_name" />
<img
v-if="config.app_logo_horizontal"
:src="$getImage(config.app_logo_horizontal)"
:alt="config.app_name"
/>
<b v-if="!config.app_logo_horizontal" class="logo-text">{{ config.app_name }}</b>
</router-link>
<div class="navigation">

View File

@@ -1,7 +1,11 @@
<template>
<footer class="page-wrapper medium">
<router-link :to="{ name: 'Homepage' }" tag="div" class="logo">
<img v-if="config.app_logo_horizontal" :src="$getImage(config.app_logo_horizontal)" :alt="config.app_name" />
<img
v-if="config.app_logo_horizontal"
:src="$getImage(config.app_logo_horizontal)"
:alt="config.app_name"
/>
<b v-if="!config.app_logo_horizontal" class="logo-text">{{ config.app_name }}</b>
</router-link>
<ul class="navigation-links">

View File

@@ -1,5 +1,8 @@
<template>
<div class="page-wrapper medium pricing" v-if="!isEmpty && index.section_pricing_content === '1' && config.stripe_public_key">
<div
class="page-wrapper medium pricing"
v-if="!isEmpty && index.section_pricing_content === '1' && config.stripe_public_key"
>
<div id="pricing" class="page-title center">
<h1 class="title" v-html="index.pricing_title"></h1>
</div>

View File

@@ -9,13 +9,13 @@
<slot />
</div>
</transition>
<transition name="vignette">
<div
v-if="isVisible"
@click="closeMenu"
class="fixed left-0 right-0 top-0 bottom-0 z-20 bg-dark-background bg-opacity-[0.35] dark:bg-opacity-[0.45]"
></div>
</transition>
<transition name="vignette">
<div
v-if="isVisible"
@click="closeMenu"
class="fixed left-0 right-0 top-0 bottom-0 z-20 bg-dark-background bg-opacity-[0.35] dark:bg-opacity-[0.45]"
></div>
</transition>
</div>
</template>
@@ -75,19 +75,19 @@ export default {
}
.vignette-enter-active {
animation: vignette-in 0.15s cubic-bezier(0.4, 0, 1, 1);
animation: vignette-in 0.15s cubic-bezier(0.4, 0, 1, 1);
}
.vignette-leave-active {
animation: vignette-in 0.15s linear reverse;
animation: vignette-in 0.15s linear reverse;
}
@keyframes vignette-in {
0% {
opacity: 0;
}
100% {
opacity: 1;
}
0% {
opacity: 0;
}
100% {
opacity: 1;
}
}
</style>

View File

@@ -23,7 +23,13 @@
<ButtonBase class="w-full" @click.native="$closePopup()" button-style="secondary">
{{ $t('global.cancel') }}
</ButtonBase>
<ButtonBase class="w-full" @click.native="confirmPassword" button-style="theme" :loading="isLoading" :disabled="isLoading">
<ButtonBase
class="w-full"
@click.native="confirmPassword"
button-style="theme"
:loading="isLoading"
:disabled="isLoading"
>
{{ $t('popup_2fa.confirm_button') }}
</ButtonBase>
</PopupActions>

View File

@@ -39,7 +39,8 @@ export default {
},
},
created() {
this.isVisibleDisclaimer = this.config.installation === 'installation-done' && !localStorage.getItem('isHiddenDisclaimer')
this.isVisibleDisclaimer =
this.config.installation === 'installation-done' && !localStorage.getItem('isHiddenDisclaimer')
},
}
</script>

View File

@@ -21,7 +21,11 @@
</AppInputText>
</ValidationProvider>
<AppInputSwitch :title="$t('Emoji as an Icon')" :description="$t('Replace folder icon with an Emoji')" :is-last="!isEmoji">
<AppInputSwitch
:title="$t('Emoji as an Icon')"
:description="$t('Replace folder icon with an Emoji')"
:is-last="!isEmoji"
>
<SwitchInput v-model="isEmoji" :state="isEmoji" />
</AppInputSwitch>
@@ -32,8 +36,12 @@
<!--Actions-->
<PopupActions>
<ButtonBase class="w-full" @click.native="$closePopup()" button-style="secondary">{{ $t('popup_move_item.cancel') }} </ButtonBase>
<ButtonBase class="w-full" @click.native="createFolder" button-style="theme">{{ $t('popup_create_folder.title') }} </ButtonBase>
<ButtonBase class="w-full" @click.native="$closePopup()" button-style="secondary"
>{{ $t('popup_move_item.cancel') }}
</ButtonBase>
<ButtonBase class="w-full" @click.native="createFolder" button-style="theme"
>{{ $t('popup_create_folder.title') }}
</ButtonBase>
</PopupActions>
</PopupWrapper>
</template>

View File

@@ -7,9 +7,20 @@
<PopupContent>
<!--Form to set sharing-->
<ValidationObserver @submit.prevent="createLanguage" ref="createForm" v-slot="{ invalid }" tag="form">
<ValidationProvider tag="div" mode="passive" name="Language Locale" rules="required" v-slot="{ errors }">
<ValidationProvider
tag="div"
mode="passive"
name="Language Locale"
rules="required"
v-slot="{ errors }"
>
<AppInputText :title="$t('select_locale')" :error="errors[0]">
<SelectInput v-model="form.locale" :options="locales" :placeholder="$t('select_language_locale')" :isError="errors[0]" />
<SelectInput
v-model="form.locale"
:options="locales"
:placeholder="$t('select_language_locale')"
:isError="errors[0]"
/>
</AppInputText>
</ValidationProvider>
<ValidationProvider tag="div" mode="passive" name="Language Name" rules="required" v-slot="{ errors }">
@@ -32,7 +43,13 @@
<ButtonBase class="w-full" @click.native="$closePopup()" button-style="secondary">
{{ $t('global.cancel') }}
</ButtonBase>
<ButtonBase class="w-full" @click.native="createLanguage" button-style="theme" :loading="isLoading" :disabled="isLoading">
<ButtonBase
class="w-full"
@click.native="createLanguage"
button-style="theme"
:loading="isLoading"
:disabled="isLoading"
>
{{ $t('create_language') }}
</ButtonBase>
</PopupActions>

View File

@@ -3,7 +3,13 @@
<PopupHeader :title="$t('popup_personal_token.title')" icon="key" />
<PopupContent>
<ValidationObserver v-if="!token" @submit.prevent="createTokenForm" ref="createToken" v-slot="{ invalid }" tag="form">
<ValidationObserver
v-if="!token"
@submit.prevent="createTokenForm"
ref="createToken"
v-slot="{ invalid }"
tag="form"
>
<ValidationProvider tag="div" mode="passive" name="Token Name" rules="required" v-slot="{ errors }">
<AppInputText :title="$t('popup_personal_token.label')" :error="errors[0]" :is-last="true">
<input
@@ -31,7 +37,13 @@
<ButtonBase class="w-full" @click.native="$closePopup()" button-style="secondary">
{{ $t('global.cancel') }}
</ButtonBase>
<ButtonBase class="w-full" @click.native="createTokenForm" button-style="theme" :loading="isLoading" :disabled="isLoading">
<ButtonBase
class="w-full"
@click.native="createTokenForm"
button-style="theme"
:loading="isLoading"
:disabled="isLoading"
>
{{ $t('personal_token.create_token') }}
</ButtonBase>
</PopupActions>

View File

@@ -1,6 +1,10 @@
<template>
<div v-if="emoji">
<div v-if="config.defaultEmoji === 'twemoji'" v-html="transferEmoji" style="font-size: inherit; transform: scale(0.95)"></div>
<div
v-if="config.defaultEmoji === 'twemoji'"
v-html="transferEmoji"
style="font-size: inherit; transform: scale(0.95)"
></div>
<div v-if="config.defaultEmoji === 'applemoji'" style="font-size: inherit">
{{ emoji.char }}
</div>

View File

@@ -8,7 +8,13 @@
</div>
<!-- Search input -->
<input @click="openList" v-model="query" class="focus-border-theme input-dark" type="text" :placeholder="$t('Select or search emoji icon...')" />
<input
@click="openList"
v-model="query"
class="focus-border-theme input-dark"
type="text"
:placeholder="$t('Select or search emoji icon...')"
/>
</div>
<!-- Spinner -->
@@ -17,9 +23,18 @@
</div>
<!-- Emojis List -->
<div v-if="isOpen && isLoaded && emojis" @scroll="checkGroupInView" id="group-box" class="relative h-96 select-none overflow-y-auto lg:h-60 2xl:h-96">
<div
v-if="isOpen && isLoaded && emojis"
@scroll="checkGroupInView"
id="group-box"
class="relative h-96 select-none overflow-y-auto lg:h-60 2xl:h-96"
>
<!-- Navigation of Emojis Groups -->
<ul v-if="!query" class="sticky top-0 z-10 flex items-center justify-between space-x-1 bg-white dark:bg-dark-background sm:dark:bg-4x-dark-foreground" id="group-bar">
<ul
v-if="!query"
class="sticky top-0 z-10 flex items-center justify-between space-x-1 bg-white dark:bg-dark-background sm:dark:bg-4x-dark-foreground"
id="group-bar"
>
<li
@click.stop="scrollToGroup(group.name)"
v-for="(group, i) in emojis.groups"
@@ -39,7 +54,12 @@
{{ name }}
</label>
<ul class="space-between grid grid-cols-7 gap-4 md:grid-cols-9">
<li @click="setEmoji(emoji)" v-for="(emoji, i) in group" :key="i" class="flex cursor-pointer items-center justify-center">
<li
@click="setEmoji(emoji)"
v-for="(emoji, i) in group"
:key="i"
class="flex cursor-pointer items-center justify-center"
>
<Emoji :emoji="emoji" class="text-4xl" />
</li>
</ul>
@@ -47,7 +67,12 @@
<!-- Searched emojis -->
<ul v-if="query" class="space-between grid grid-cols-7 gap-4 md:grid-cols-9">
<li @click="setEmoji(emoji)" v-for="(emoji, i) in filteredEmojis" :key="i" class="flex cursor-pointer items-center justify-center">
<li
@click="setEmoji(emoji)"
v-for="(emoji, i) in filteredEmojis"
:key="i"
class="flex cursor-pointer items-center justify-center"
>
<Emoji :emoji="emoji" class="text-4xl" />
</li>
</ul>

View File

@@ -9,10 +9,24 @@
/>
<!--Audio-->
<audio v-if="singleFile.data.type === 'audio'" :src="singleFile.data.attributes.file_url" controlsList="nodownload" controls class="w-full"></audio>
<audio
v-if="singleFile.data.type === 'audio'"
:src="singleFile.data.attributes.file_url"
controlsList="nodownload"
controls
class="w-full"
></audio>
<!--Video-->
<video v-if="singleFile.data.type === 'video'" ref="video" class="h-auto w-full overflow-hidden rounded-sm" controlsList="nodownload" disablePictureInPicture playsinline controls>
<video
v-if="singleFile.data.type === 'video'"
ref="video"
class="h-auto w-full overflow-hidden rounded-sm"
controlsList="nodownload"
disablePictureInPicture
playsinline
controls
>
<source :src="singleFile.data.attributes.file_url" type="video/mp4" />
</video>
</div>
@@ -33,12 +47,12 @@ export default {
return this.singleFile && !includes(['folder', 'file'], this.singleFile.data.type)
},
},
watch: {
'singleFile': function (val) {
if (val.data.type === 'video') {
this.$refs.video.load()
}
}
}
watch: {
singleFile: function (val) {
if (val.data.type === 'video') {
this.$refs.video.load()
}
},
},
}
</script>

View File

@@ -1,7 +1,18 @@
<template>
<div class="relative cursor-pointer">
<input ref="file" type="file" @change="showImagePreview($event)" class="absolute top-0 bottom-0 left-0 right-0 z-10 w-full cursor-pointer opacity-0" />
<img v-if="imagePreview" ref="image" :src="imagePreview" class="relative z-0 h-14 w-14 cursor-pointer rounded-xl object-cover shadow-lg md:h-16 md:w-16" alt="avatar" />
<input
ref="file"
type="file"
@change="showImagePreview($event)"
class="absolute top-0 bottom-0 left-0 right-0 z-10 w-full cursor-pointer opacity-0"
/>
<img
v-if="imagePreview"
ref="image"
:src="imagePreview"
class="relative z-0 h-14 w-14 cursor-pointer rounded-xl object-cover shadow-lg md:h-16 md:w-16"
alt="avatar"
/>
</div>
</template>

View File

@@ -21,7 +21,10 @@
</div>
<!--Hidden options-->
<ul v-if="isOpenedMoreOptions" class="absolute top-12 left-0 right-0 z-10 select-none overflow-y-auto overflow-x-hidden rounded-lg shadow-xl">
<ul
v-if="isOpenedMoreOptions"
class="absolute top-12 left-0 right-0 z-10 select-none overflow-y-auto overflow-x-hidden rounded-lg shadow-xl"
>
<li
@click="getQrCode"
class="block flex cursor-pointer items-center bg-white py-2.5 px-5 hover:bg-light-background dark:bg-2x-dark-foreground dark:hover:bg-4x-dark-foreground"
@@ -57,7 +60,11 @@
</li>
</ul>
<textarea v-model="iframeCode" ref="iframe" class="pointer-events-none absolute right-full opacity-0"></textarea>
<textarea
v-model="iframeCode"
ref="iframe"
class="pointer-events-none absolute right-full opacity-0"
></textarea>
</div>
</template>

View File

@@ -23,8 +23,8 @@
<script>
import {
InfoIcon,
DatabaseIcon,
InfoIcon,
DatabaseIcon,
UsersIcon,
ShieldIcon,
CreditCardIcon,
@@ -44,8 +44,8 @@ export default {
name: 'FormLabel',
props: ['icon'],
components: {
InfoIcon,
DatabaseIcon,
InfoIcon,
DatabaseIcon,
UsersIcon,
CreditCardIcon,
DollarSignIcon,

View File

@@ -1,86 +1,97 @@
<template>
<div class="flex items-center justify-center rounded-lg relative h-[175px] dark:bg-2x-dark-foreground bg-light-background" :class="{ 'is-error': error }">
<!--Reset Image-->
<div
v-if="imagePreview"
@click="resetImage"
class="absolute z-10 right-0 top-0 flex h-7 w-7 cursor-pointer items-center justify-center rounded-md bg-white shadow-lg rounded-full -translate-y-3 translate-x-3"
>
<div
class="relative flex h-[175px] items-center justify-center rounded-lg bg-light-background dark:bg-2x-dark-foreground"
:class="{ 'is-error': error }"
>
<!--Reset Image-->
<div
v-if="imagePreview"
@click="resetImage"
class="absolute right-0 top-0 z-10 flex h-7 w-7 -translate-y-3 translate-x-3 cursor-pointer items-center justify-center rounded-md rounded-full bg-white shadow-lg"
>
<x-icon size="14" class="vue-feather" />
</div>
</div>
<input
@change="showImagePreview($event)"
ref="file"
type="file"
class="opacity-0 absolute top-0 left-0 right-0 bottom-0 z-10 w-full cursor-pointer"
/>
@change="showImagePreview($event)"
ref="file"
type="file"
class="absolute top-0 left-0 right-0 bottom-0 z-10 w-full cursor-pointer opacity-0"
/>
<!--Default image preview-->
<img v-if="imagePreview" :src="imagePreview" ref="image" class="absolute w-full h-full object-contain py-4 px-12" />
<!--Default image preview-->
<img
v-if="imagePreview"
:src="imagePreview"
ref="image"
class="absolute h-full w-full object-contain py-4 px-12"
/>
<!--Drop image zone-->
<!--Drop image zone-->
<div v-if="!isData" class="text-center">
<image-icon size="34" class="vue-feather text-theme inline-block mb-4" />
<image-icon size="34" class="vue-feather text-theme mb-4 inline-block" />
<b class="font-bold text-base block leading-3">
<b class="block text-base font-bold leading-3">
{{ $te('input_image.title') ? $t('input_image.title') : 'Upload Image' }}
</b>
<small class="text-xs text-gray-500">
{{ $te('input_image.supported') ? $t('input_image.supported') : 'Supported formats are .png, .jpg, .jpeg.' }}
{{
$te('input_image.supported')
? $t('input_image.supported')
: 'Supported formats are .png, .jpg, .jpeg.'
}}
</small>
</div>
</div>
</template>
<script>
import {XIcon, ImageIcon} from 'vue-feather-icons'
import { XIcon, ImageIcon } from 'vue-feather-icons'
export default {
name: 'ImageInput',
props: ['image', 'error'],
components: {
ImageIcon,
XIcon,
},
data() {
return {
imagePreview: undefined,
}
},
computed: {
isData() {
return !(typeof this.imagePreview === 'undefined' || this.imagePreview === '')
},
},
methods: {
resetImage() {
this.imagePreview = undefined
this.$emit('input', undefined)
},
showImagePreview(event) {
const imgPath = event.target.files[0].name,
extn = imgPath.substring(imgPath.lastIndexOf('.') + 1).toLowerCase()
name: 'ImageInput',
props: ['image', 'error'],
components: {
ImageIcon,
XIcon,
},
data() {
return {
imagePreview: undefined,
}
},
computed: {
isData() {
return !(typeof this.imagePreview === 'undefined' || this.imagePreview === '')
},
},
methods: {
resetImage() {
this.imagePreview = undefined
this.$emit('input', undefined)
},
showImagePreview(event) {
const imgPath = event.target.files[0].name,
extn = imgPath.substring(imgPath.lastIndexOf('.') + 1).toLowerCase()
if (['png', 'jpg', 'jpeg', 'svg'].includes(extn)) {
const file = event.target.files[0],
reader = new FileReader()
if (['png', 'jpg', 'jpeg', 'svg'].includes(extn)) {
const file = event.target.files[0],
reader = new FileReader()
reader.onload = () => (this.imagePreview = reader.result)
reader.onload = () => (this.imagePreview = reader.result)
reader.readAsDataURL(file)
reader.readAsDataURL(file)
// Update user avatar
this.$emit('input', event.target.files[0])
} else {
alert(this.$t('validation_errors.wrong_image'))
}
},
},
created() {
// If has default image then load
if (this.image) this.imagePreview = this.image
},
// Update user avatar
this.$emit('input', event.target.files[0])
} else {
alert(this.$t('validation_errors.wrong_image'))
}
},
},
created() {
// If has default image then load
if (this.image) this.imagePreview = this.image
},
}
</script>

View File

@@ -7,9 +7,7 @@
<script>
export default {
name: 'InfoBox',
props: [
'type'
],
props: ['type'],
}
</script>

View File

@@ -1,9 +1,18 @@
<template>
<div class="wrapper">
<!--<label class="input-label">{{ label }}:</label>-->
<div class="input-wrapper focus-within-border-theme" :class="{ 'is-error': isError }" @click="$refs.input.focus()">
<div
class="input-wrapper focus-within-border-theme"
:class="{ 'is-error': isError }"
@click="$refs.input.focus()"
>
<div class="email-list">
<div class="email-tag bg-theme-100" :class="{ 'mb-offset': getCharactersLength > 45 }" v-for="(email, i) in emails" :key="i">
<div
class="email-tag bg-theme-100"
:class="{ 'mb-offset': getCharactersLength > 45 }"
v-for="(email, i) in emails"
:key="i"
>
<span class="text-theme">{{ email }}</span>
<x-icon @click="removeEmail(email)" class="icon" size="14" />
</div>

View File

@@ -6,7 +6,14 @@
<div @click="clearInput" v-if="query" class="icon">
<x-icon class="pointer" size="19"></x-icon>
</div>
<input v-model="query" @input="$emit('input', query)" class="query focus-border-theme" type="text" name="searchInput" :placeholder="$t('search_translations')" />
<input
v-model="query"
@input="$emit('input', query)"
class="query focus-border-theme"
type="text"
name="searchInput"
:placeholder="$t('search_translations')"
/>
</div>
</template>

View File

@@ -1,6 +1,12 @@
<template>
<div class="select-box">
<div class="box-item active-bg-theme-100 active-border-theme" :class="{ active: item.value === input }" @click="getSelectedValue(item)" v-for="(item, i) in data" :key="i">
<div
class="box-item active-bg-theme-100 active-border-theme"
:class="{ active: item.value === input }"
@click="getSelectedValue(item)"
v-for="(item, i) in data"
:key="i"
>
<span class="box-value active-text-theme">{{ item.label }}</span>
</div>
</div>

View File

@@ -1,7 +1,11 @@
<template>
<div class="select">
<!--Area-->
<div class="input-area rounded-lg dark:bg-2x-dark-foreground bg-light-background" :class="{ 'is-active': isOpen, 'is-error': isError }" @click="openMenu">
<div
class="input-area rounded-lg bg-light-background dark:bg-2x-dark-foreground"
:class="{ 'is-active': isOpen, 'is-error': isError }"
@click="openMenu"
>
<!--If is selected-->
<div class="selected flex w-full items-center" v-if="selected">
<div class="option-icon" v-if="selected.icon">
@@ -25,7 +29,13 @@
<transition name="slide-in">
<div class="input-options rounded-lg" v-if="isOpen">
<div v-if="options.length > 5" class="select-search">
<input v-model="query" ref="search" type="text" :placeholder="$t('select_search_placeholder')" class="search-input focus-border-theme rounded-lg" />
<input
v-model="query"
ref="search"
type="text"
:placeholder="$t('select_search_placeholder')"
class="search-input focus-border-theme rounded-lg"
/>
</div>
<ul class="option-list">
<li class="option-item" @click="selectOption(option)" v-for="(option, i) in optionList" :key="i">

View File

@@ -4,7 +4,10 @@
<UserHeadline v-if="!clickedSubmenu" class="p-5 pb-3" />
<!--User estimate-->
<div v-if="config.subscriptionType === 'metered' && user && user.data.meta.usages && !clickedSubmenu" class="block px-5 pt-2">
<div
v-if="config.subscriptionType === 'metered' && user && user.data.meta.usages && !clickedSubmenu"
class="block px-5 pt-2"
>
<div class="rounded-lg bg-light-background px-3 py-1.5 dark:bg-4x-dark-foreground">
<span class="text-sm font-semibold">
{{ $t('Your current estimated usage:') }}
@@ -27,9 +30,27 @@
<MenuMobileGroup>
<!--Main navigation-->
<OptionGroup v-if="!clickedSubmenu">
<Option @click.native="goToFiles" :title="$t('menu.files')" icon="hard-drive" :is-hover-disabled="true" />
<Option @click.native.stop="showSubmenu('settings')" :title="$t('menu.settings')" icon="user" arrow="right" :is-hover-disabled="true" />
<Option v-if="isAdmin" @click.native.stop="showSubmenu('admin')" :title="$t('menu.admin')" icon="settings" arrow="right" :is-hover-disabled="true" />
<Option
@click.native="goToFiles"
:title="$t('menu.files')"
icon="hard-drive"
:is-hover-disabled="true"
/>
<Option
@click.native.stop="showSubmenu('settings')"
:title="$t('menu.settings')"
icon="user"
arrow="right"
:is-hover-disabled="true"
/>
<Option
v-if="isAdmin"
@click.native.stop="showSubmenu('admin')"
:title="$t('menu.admin')"
icon="settings"
arrow="right"
:is-hover-disabled="true"
/>
</OptionGroup>
<OptionGroup v-if="!clickedSubmenu">
<Option @click.native="logOut" :title="$t('menu.logout')" icon="power" :is-hover-disabled="true" />
@@ -37,28 +58,79 @@
<!--Submenu: User settings-->
<OptionGroup v-if="clickedSubmenu === 'settings'">
<Option @click.native="goToRoute('Profile')" :title="$t('menu.profile')" icon="user" :is-hover-disabled="true" />
<Option @click.native="goToRoute('Password')" :title="$t('menu.password')" icon="lock" :is-hover-disabled="true" />
<Option @click.native="goToRoute('Storage')" :title="$t('menu.storage')" icon="hard-drive" :is-hover-disabled="true" />
<Option @click.native="goToRoute('Billing')" v-if="config.subscriptionType !== 'none'" :title="$t('Billing')" icon="cloud" :is-hover-disabled="true" />
<Option
@click.native="goToRoute('Profile')"
:title="$t('menu.profile')"
icon="user"
:is-hover-disabled="true"
/>
<Option
@click.native="goToRoute('Password')"
:title="$t('menu.password')"
icon="lock"
:is-hover-disabled="true"
/>
<Option
@click.native="goToRoute('Storage')"
:title="$t('menu.storage')"
icon="hard-drive"
:is-hover-disabled="true"
/>
<Option
@click.native="goToRoute('Billing')"
v-if="config.subscriptionType !== 'none'"
:title="$t('Billing')"
icon="cloud"
:is-hover-disabled="true"
/>
</OptionGroup>
<!--Submenu: Admin settings-->
<OptionGroup v-if="clickedSubmenu === 'admin'">
<Option @click.native="goToRoute('Dashboard')" :title="$t('admin_menu.dashboard')" icon="box" :is-hover-disabled="true" />
<Option @click.native="goToRoute('Users')" :title="$t('admin_menu.users')" icon="users" :is-hover-disabled="true" />
<Option @click.native="goToRoute('AppOthers')" :title="$t('admin_menu.settings')" icon="settings" :is-hover-disabled="true" />
<Option
@click.native="goToRoute('Dashboard')"
:title="$t('admin_menu.dashboard')"
icon="box"
:is-hover-disabled="true"
/>
<Option
@click.native="goToRoute('Users')"
:title="$t('admin_menu.users')"
icon="users"
:is-hover-disabled="true"
/>
<Option
@click.native="goToRoute('AppOthers')"
:title="$t('admin_menu.settings')"
icon="settings"
:is-hover-disabled="true"
/>
</OptionGroup>
<!--Submenu: Content settings-->
<OptionGroup v-if="clickedSubmenu === 'admin'">
<Option @click.native="goToRoute('Pages')" :title="$t('admin_menu.pages')" icon="monitor" :is-hover-disabled="true" />
<Option @click.native="goToRoute('Language')" :title="$t('languages')" icon="globe" :is-hover-disabled="true" />
<Option
@click.native="goToRoute('Pages')"
:title="$t('admin_menu.pages')"
icon="monitor"
:is-hover-disabled="true"
/>
<Option
@click.native="goToRoute('Language')"
:title="$t('languages')"
icon="globe"
:is-hover-disabled="true"
/>
</OptionGroup>
<!--Submenu: Billing settings-->
<OptionGroup v-if="clickedSubmenu === 'admin' && config.subscriptionType !== 'none'">
<Option @click.native="goToRoute('AppPayments')" :title="$t('Payments')" icon="credit-card" :is-hover-disabled="true" />
<Option
@click.native="goToRoute('AppPayments')"
:title="$t('Payments')"
icon="credit-card"
:is-hover-disabled="true"
/>
<Option
@click.native="goToRoute('Subscriptions')"
v-if="config.subscriptionType === 'fixed'"
@@ -66,8 +138,18 @@
icon="credit-card"
:is-hover-disabled="true"
/>
<Option @click.native="goToRoute('Plans')" :title="$t('admin_menu.plans')" icon="database" :is-hover-disabled="true" />
<Option @click.native="goToRoute('Invoices')" :title="$t('Transactions')" icon="file-text" :is-hover-disabled="true" />
<Option
@click.native="goToRoute('Plans')"
:title="$t('admin_menu.plans')"
icon="database"
:is-hover-disabled="true"
/>
<Option
@click.native="goToRoute('Invoices')"
:title="$t('Transactions')"
icon="file-text"
:is-hover-disabled="true"
/>
</OptionGroup>
</MenuMobileGroup>
</MenuMobile>

View File

@@ -20,14 +20,25 @@
v-if="clipboard.length > 1 && !isSelectedItem"
/>
<TreeMenu class="-mx-4" :disabled-by-id="pickedItem" :depth="1" :nodes="items" v-for="items in navigation" :key="items.id" />
<TreeMenu
class="-mx-4"
:disabled-by-id="pickedItem"
:depth="1"
:nodes="items"
v-for="items in navigation"
:key="items.id"
/>
</div>
</PopupContent>
<!--Actions-->
<PopupActions>
<ButtonBase class="w-full" @click.native="$closePopup()" button-style="secondary">{{ $t('popup_move_item.cancel') }} </ButtonBase>
<ButtonBase class="w-full" @click.native="moveItem" :button-style="selectedFolder ? 'theme' : 'secondary'">{{ $t('popup_move_item.submit') }} </ButtonBase>
<ButtonBase class="w-full" @click.native="$closePopup()" button-style="secondary"
>{{ $t('popup_move_item.cancel') }}
</ButtonBase>
<ButtonBase class="w-full" @click.native="moveItem" :button-style="selectedFolder ? 'theme' : 'secondary'"
>{{ $t('popup_move_item.submit') }}
</ButtonBase>
</PopupActions>
</PopupWrapper>
</template>
@@ -76,7 +87,11 @@ export default {
if (!this.selectedFolder) return
// Prevent to move items to the same parent
if (isArray(this.selectedFolder) && this.clipboard.find((item) => item.parent_id === this.selectedFolder.id)) return
if (
isArray(this.selectedFolder) &&
this.clipboard.find((item) => item.parent_id === this.selectedFolder.id)
)
return
// Move item
if (!this.isSelectedItem) {

View File

@@ -18,9 +18,16 @@
<footer class="plan-footer">
<b class="price text-theme">
{{ plan.data.attributes.price }}/{{ $t('global.monthly_ac') }}
<small v-if="plan.data.attributes.tax_rates.length > 0" class="vat-disclaimer">{{ $t('page_pricing_tables.vat_excluded') }}</small>
<small v-if="plan.data.attributes.tax_rates.length > 0" class="vat-disclaimer">{{
$t('page_pricing_tables.vat_excluded')
}}</small>
</b>
<ButtonBase @click.native="selectPlan(plan)" type="submit" button-style="secondary" class="sign-in-button">
<ButtonBase
@click.native="selectPlan(plan)"
type="submit"
button-style="secondary"
class="sign-in-button"
>
{{ $t('global.get_it') }}
</ButtonBase>
</footer>

View File

@@ -14,8 +14,12 @@
</div>
<PopupActions>
<ButtonBase @click.native="closePopup" button-style="secondary" class="w-full">{{ $t('global.cancel') }} </ButtonBase>
<ButtonBase @click.native="confirm" :button-style="buttonColor" class="w-full">{{ $t('global.confirm_action') }} </ButtonBase>
<ButtonBase @click.native="closePopup" button-style="secondary" class="w-full"
>{{ $t('global.cancel') }}
</ButtonBase>
<ButtonBase @click.native="confirm" :button-style="buttonColor" class="w-full"
>{{ $t('global.confirm_action') }}
</ButtonBase>
</PopupActions>
</PopupWrapper>
</template>

View File

@@ -1,5 +1,8 @@
<template>
<div :class="type" class="absolute top-16 bottom-24 left-0 right-0 h-auto overflow-x-auto overflow-y-auto px-6 md:relative md:top-0 md:bottom-0">
<div
:class="type"
class="absolute top-16 bottom-24 left-0 right-0 h-auto overflow-x-auto overflow-y-auto px-6 md:relative md:top-0 md:bottom-0"
>
<slot />
</div>
</template>

View File

@@ -22,7 +22,17 @@
</template>
<script>
import { CreditCardIcon, KeyIcon, UserPlusIcon, CornerDownRightIcon, LinkIcon, XIcon, Edit2Icon, ShareIcon, UsersIcon } from 'vue-feather-icons'
import {
CreditCardIcon,
KeyIcon,
UserPlusIcon,
CornerDownRightIcon,
LinkIcon,
XIcon,
Edit2Icon,
ShareIcon,
UsersIcon,
} from 'vue-feather-icons'
import { events } from '../../../bus'
export default {

View File

@@ -1,7 +1,13 @@
<template>
<transition name="popup">
<div v-if="isVisibleWrapper" @click.self="closePopup" class="popup z-50 fixed top-0 left-0 right-0 bottom-0 grid h-full overflow-y-auto p-10 lg:absolute">
<div class="fixed md:relative top-0 bottom-0 left-0 right-0 w-full dark:bg-2x-dark-foreground bg-white m-auto z-10 md:w-[490px] md:rounded-xl shadow-xl">
<div
v-if="isVisibleWrapper"
@click.self="closePopup"
class="popup fixed top-0 left-0 right-0 bottom-0 z-50 grid h-full overflow-y-auto p-10 lg:absolute"
>
<div
class="fixed top-0 bottom-0 left-0 right-0 z-10 m-auto w-full bg-white shadow-xl dark:bg-2x-dark-foreground md:relative md:w-[490px] md:rounded-xl"
>
<slot />
</div>
</div>
@@ -44,41 +50,40 @@ export default {
</script>
<style lang="scss" scoped>
.popup-leave-active {
animation: popup-slide-in 0.15s ease reverse;
}
.popup-leave-active {
animation: popup-slide-in 0.15s ease reverse;
}
@media only screen and (min-width: 960px) {
.popup-enter-active {
animation: popup-slide-in 0.25s 0.1s ease both;
}
@media only screen and (min-width: 960px) {
.popup-enter-active {
animation: popup-slide-in 0.25s 0.10s ease both;
}
@keyframes popup-slide-in {
0% {
opacity: 0;
transform: translateY(100px);
}
@keyframes popup-slide-in {
0% {
opacity: 0;
transform: translateY(100px);
}
100% {
opacity: 1;
transform: translateY(0);
}
}
}
100% {
opacity: 1;
transform: translateY(0);
}
}
}
@media only screen and (max-width: 960px) {
.popup-enter-active {
animation: popup-slide-in 0.35s 0.15s ease both;
}
@media only screen and (max-width: 960px) {
.popup-enter-active {
animation: popup-slide-in 0.35s 0.15s ease both;
}
@keyframes popup-slide-in {
0% {
transform: translateY(100%);
}
100% {
transform: translateY(0);
}
}
}
@keyframes popup-slide-in {
0% {
transform: translateY(100%);
}
100% {
transform: translateY(0);
}
}
}
</style>

View File

@@ -12,7 +12,11 @@
<ValidationObserver @submit.prevent="changeName" ref="renameForm" v-slot="{ invalid }" tag="form">
<!--Update item name-->
<ValidationProvider tag="div" mode="passive" name="Name" rules="required" v-slot="{ errors }">
<AppInputText :title="$t('popup_rename.label')" :error="errors[0]" :is-last="pickedItem.data.type !== 'folder'">
<AppInputText
:title="$t('popup_rename.label')"
:error="errors[0]"
:is-last="pickedItem.data.type !== 'folder'"
>
<div class="relative flex items-center">
<input
v-model="pickedItem.data.attributes.name"
@@ -30,12 +34,21 @@
</ValidationProvider>
<!--Emoji-->
<AppInputSwitch v-if="pickedItem.data.type === 'folder'" :title="$t('Emoji as an Icon')" :description="$t('Replace folder icon with an Emoji')" :is-last="!isEmoji">
<AppInputSwitch
v-if="pickedItem.data.type === 'folder'"
:title="$t('Emoji as an Icon')"
:description="$t('Replace folder icon with an Emoji')"
:is-last="!isEmoji"
>
<SwitchInput v-model="isEmoji" :state="isEmoji" />
</AppInputSwitch>
<!--Set emoji-->
<EmojiPicker v-if="pickedItem.data.type === 'folder' && isEmoji" v-model="emoji" :default-emoji="emoji" />
<EmojiPicker
v-if="pickedItem.data.type === 'folder' && isEmoji"
v-model="emoji"
:default-emoji="emoji"
/>
</ValidationObserver>
</PopupContent>
@@ -87,7 +100,9 @@ export default {
},
computed: {
itemTypeTitle() {
return this.pickedItem && this.pickedItem.data.type === 'folder' ? this.$t('types.folder') : this.$t('types.file')
return this.pickedItem && this.pickedItem.data.type === 'folder'
? this.$t('types.folder')
: this.$t('types.file')
},
},
watch: {

View File

@@ -10,11 +10,19 @@
'mb-2 rounded-xl bg-light-background px-4 dark:bg-2x-dark-foreground': paypal.isMethodsLoaded,
}"
>
<PaymentMethod @click.native="pickedPaymentMethod('paypal')" driver="paypal" :description="config.paypal_payment_description">
<PaymentMethod
@click.native="pickedPaymentMethod('paypal')"
driver="paypal"
:description="config.paypal_payment_description"
>
<div v-if="paypal.isMethodLoading" class="translate-y-3 scale-50 transform">
<Spinner />
</div>
<span v-if="!paypal.isMethodsLoaded" :class="{ 'opacity-0': paypal.isMethodLoading }" class="text-theme cursor-pointer text-sm font-bold">
<span
v-if="!paypal.isMethodsLoaded"
:class="{ 'opacity-0': paypal.isMethodLoading }"
class="text-theme cursor-pointer text-sm font-bold"
>
{{ $t('Select') }}
</span>
</PaymentMethod>
@@ -24,7 +32,11 @@
</div>
<!--Paystack implementation-->
<PaymentMethod v-if="config.isPaystack" driver="paystack" :description="config.paystack_payment_description">
<PaymentMethod
v-if="config.isPaystack"
driver="paystack"
:description="config.paystack_payment_description"
>
<paystack
@click.native="pickedPaymentMethod('paystack')"
v-if="user && config"

View File

@@ -9,9 +9,22 @@
<ThumbnailItem class="mb-5" :item="pickedItem" />
<!--Form to set sharing-->
<ValidationObserver v-if="!isGeneratedShared" @submit.prevent ref="shareForm" v-slot="{ invalid }" tag="form">
<ValidationObserver
v-if="!isGeneratedShared"
@submit.prevent
ref="shareForm"
v-slot="{ invalid }"
tag="form"
>
<!--Permission Select-->
<ValidationProvider v-if="isFolder" tag="div" mode="passive" name="Permission" rules="required" v-slot="{ errors }">
<ValidationProvider
v-if="isFolder"
tag="div"
mode="passive"
name="Permission"
rules="required"
v-slot="{ errors }"
>
<AppInputText :title="$t('shared_form.label_permission')" :error="errors[0]">
<SelectInput
v-model="shareOptions.permission"
@@ -24,12 +37,26 @@
<!--Password Switch-->
<div>
<AppInputSwitch :title="$t('shared_form.label_password_protection')" :description="$t('popup.share.password_description')">
<SwitchInput v-model="shareOptions.isPassword" class="switch" :state="shareOptions.isPassword" />
<AppInputSwitch
:title="$t('shared_form.label_password_protection')"
:description="$t('popup.share.password_description')"
>
<SwitchInput
v-model="shareOptions.isPassword"
class="switch"
:state="shareOptions.isPassword"
/>
</AppInputSwitch>
<!--Set password-->
<ValidationProvider v-if="shareOptions.isPassword" tag="div" mode="passive" name="Password" rules="required" v-slot="{ errors }">
<ValidationProvider
v-if="shareOptions.isPassword"
tag="div"
mode="passive"
name="Password"
rules="required"
v-slot="{ errors }"
>
<AppInputText :error="errors[0]" class="-mt-2">
<input
v-model="shareOptions.password"
@@ -50,19 +77,40 @@
<!--Set expiration-->
<AppInputText v-if="isExpiration" class="-mt-2">
<SelectBoxInput v-model="shareOptions.expiration" :data="$translateSelectOptions(expirationList)" class="box" />
<SelectBoxInput
v-model="shareOptions.expiration"
:data="$translateSelectOptions(expirationList)"
class="box"
/>
</AppInputText>
</div>
<!--Send on emails switch-->
<div>
<AppInputSwitch :title="$t('popup.share.email_send')" :description="$t('popup.share.email_description')" :is-last="!isEmailSharing">
<AppInputSwitch
:title="$t('popup.share.email_send')"
:description="$t('popup.share.email_description')"
:is-last="!isEmailSharing"
>
<SwitchInput v-model="isEmailSharing" class="switch" :state="isEmailSharing" />
</AppInputSwitch>
<!--Set expiration-->
<ValidationProvider v-if="isEmailSharing" tag="div" mode="passive" name="Email" rules="required" v-slot="{ errors }" class="-mt-2">
<MultiEmailInput rules="required" v-model="shareOptions.emails" :label="$t('shared_form.recipients_label')" :isError="errors[0]" />
<ValidationProvider
v-if="isEmailSharing"
tag="div"
mode="passive"
name="Email"
rules="required"
v-slot="{ errors }"
class="-mt-2"
>
<MultiEmailInput
rules="required"
v-model="shareOptions.emails"
:label="$t('shared_form.recipients_label')"
:isError="errors[0]"
/>
</ValidationProvider>
</div>
</ValidationObserver>
@@ -78,7 +126,13 @@
<ButtonBase v-if="!isGeneratedShared" class="w-full" @click.native="$closePopup()" button-style="secondary">
{{ $t('popup_move_item.cancel') }}
</ButtonBase>
<ButtonBase class="w-full" @click.native="submitShareOptions" button-style="theme" :loading="isLoading" :disabled="isLoading">
<ButtonBase
class="w-full"
@click.native="submitShareOptions"
button-style="theme"
:loading="isLoading"
:disabled="isLoading"
>
{{ submitButtonText }}
</ButtonBase>
</PopupActions>
@@ -135,7 +189,9 @@ export default {
computed: {
...mapGetters(['permissionOptions', 'expirationList']),
itemTypeTitle() {
return this.pickedItem && this.pickedItem.data.type === 'folder' ? this.$t('types.folder') : this.$t('types.file')
return this.pickedItem && this.pickedItem.data.type === 'folder'
? this.$t('types.folder')
: this.$t('types.file')
},
isFolder() {
return this.pickedItem && this.pickedItem.data.type === 'folder'

View File

@@ -31,7 +31,11 @@
<ValidationObserver @submit.prevent v-slot="{ invalid }" ref="shareEmail" tag="form">
<ValidationProvider tag="div" mode="passive" name="Email" rules="required" v-slot="{ errors }">
<AppInputText title="Share with" :error="errors[0]" :is-last="true">
<MultiEmailInput rules="required" v-model="emails" :label="$t('shared_form.label_send_to_recipients')" />
<MultiEmailInput
rules="required"
v-model="emails"
:label="$t('shared_form.label_send_to_recipients')"
/>
</AppInputText>
</ValidationProvider>
</ValidationObserver>
@@ -41,7 +45,13 @@
<ButtonBase class="w-full" @click.native="showSection(undefined)" button-style="secondary">
{{ $t('Show Details') }}
</ButtonBase>
<ButtonBase class="w-full" @click.native="sendViaEmail" button-style="theme" :loading="isLoading" :disabled="isLoading">
<ButtonBase
class="w-full"
@click.native="sendViaEmail"
button-style="theme"
:loading="isLoading"
:disabled="isLoading"
>
{{ $t('Send') }}
</ButtonBase>
</PopupActions>
@@ -60,7 +70,14 @@
<ValidationObserver @submit.prevent ref="shareForm" v-slot="{ invalid }" tag="form">
<!--Permission Select-->
<ValidationProvider v-if="isFolder" tag="div" mode="passive" name="Permission" rules="required" v-slot="{ errors }">
<ValidationProvider
v-if="isFolder"
tag="div"
mode="passive"
name="Permission"
rules="required"
v-slot="{ errors }"
>
<AppInputText :title="$t('shared_form.label_permission')" :error="errors[0]">
<SelectInput
v-model="shareOptions.permission"
@@ -74,12 +91,23 @@
<!--Password Switch-->
<div>
<AppInputSwitch :title="$t('shared_form.label_password_protection')" :description="$t('popup.share.password_description')">
<SwitchInput v-model="shareOptions.isProtected" class="switch" :state="shareOptions.isProtected" />
<AppInputSwitch
:title="$t('shared_form.label_password_protection')"
:description="$t('popup.share.password_description')"
>
<SwitchInput
v-model="shareOptions.isProtected"
class="switch"
:state="shareOptions.isProtected"
/>
</AppInputSwitch>
<ActionButton
v-if="pickedItem.data.relationships.shared.data.attributes.protected && canChangePassword && shareOptions.isProtected"
v-if="
pickedItem.data.relationships.shared.data.attributes.protected &&
canChangePassword &&
shareOptions.isProtected
"
@click.native="changePassword"
class="mb-6 -mt-4"
>
@@ -87,7 +115,14 @@
</ActionButton>
<!--Set password-->
<ValidationProvider v-if="shareOptions.isProtected && !canChangePassword" tag="div" mode="passive" name="Password" rules="required" v-slot="{ errors }">
<ValidationProvider
v-if="shareOptions.isProtected && !canChangePassword"
tag="div"
mode="passive"
name="Password"
rules="required"
v-slot="{ errors }"
>
<AppInputText :error="errors[0]" class="-mt-2">
<input
v-model="shareOptions.password"
@@ -102,23 +137,48 @@
<!--Expiration switch-->
<div>
<AppInputSwitch :title="$t('expiration')" :description="$t('popup.share.expiration_description')" :is-last="!shareOptions.expiration">
<SwitchInput v-model="shareOptions.expiration" class="switch" :state="shareOptions.expiration ? 1 : 0" />
<AppInputSwitch
:title="$t('expiration')"
:description="$t('popup.share.expiration_description')"
:is-last="!shareOptions.expiration"
>
<SwitchInput
v-model="shareOptions.expiration"
class="switch"
:state="shareOptions.expiration ? 1 : 0"
/>
</AppInputSwitch>
<!--Set expiration-->
<AppInputText v-if="shareOptions.expiration" class="-mt-2" :is-last="true">
<SelectBoxInput v-model="shareOptions.expiration" :data="$translateSelectOptions(expirationList)" :value="shareOptions.expiration" class="box" />
<SelectBoxInput
v-model="shareOptions.expiration"
:data="$translateSelectOptions(expirationList)"
:value="shareOptions.expiration"
class="box"
/>
</AppInputText>
</div>
</ValidationObserver>
</PopupContent>
<PopupActions>
<ButtonBase class="w-full" @click.native="destroySharing" :button-style="destroyButtonStyle" :loading="isDeleting" :disabled="isDeleting">
<ButtonBase
class="w-full"
@click.native="destroySharing"
:button-style="destroyButtonStyle"
:loading="isDeleting"
:disabled="isDeleting"
>
{{ destroyButtonText }}
</ButtonBase>
<ButtonBase class="w-full" @click.native="updateShareOptions" button-style="theme" :loading="isLoading" :disabled="isLoading">
<ButtonBase
class="w-full"
@click.native="updateShareOptions"
button-style="theme"
:loading="isLoading"
:disabled="isLoading"
>
{{ $t('Store Changes') }}
</ButtonBase>
</PopupActions>

View File

@@ -1,7 +1,13 @@
<template>
<div>
<div class="tab-wrapper">
<div class="tab" :class="{ active: tab.isActive }" @click="selectTab(tab)" v-for="(tab, i) in tabs" :key="i">
<div
class="tab"
:class="{ active: tab.isActive }"
@click="selectTab(tab)"
v-for="(tab, i) in tabs"
:key="i"
>
<!--Icon-->
<mail-icon v-if="tab.icon === 'email'" class="tab-icon text-theme dark-text-theme" size="17" />
<link-icon v-if="tab.icon === 'link'" class="tab-icon text-theme dark-text-theme" size="17" />

View File

@@ -55,7 +55,12 @@
</a>
</li>
<li v-for="(page, index) in data.meta.last_page" :key="index" class="inline-block p-1" @click="goToPage(page)">
<li
v-for="(page, index) in data.meta.last_page"
:key="index"
class="inline-block p-1"
@click="goToPage(page)"
>
<a
class="page-link"
:class="{
@@ -100,7 +105,13 @@
<a class="page-link"> 1 </a>
</li>
<li v-if="pageIndex < 5" v-for="(page, index) in 5" :key="index" class="inline-block p-1" @click="goToPage(page)">
<li
v-if="pageIndex < 5"
v-for="(page, index) in 5"
:key="index"
class="inline-block p-1"
@click="goToPage(page)"
>
<a
class="page-link"
:class="{
@@ -116,7 +127,13 @@
</li>
<!--Floated Pages-->
<li v-if="pageIndex >= 5 && pageIndex < data.meta.last_page - 3" v-for="(page, index) in floatPages" :key="index" class="inline-block p-1" @click="goToPage(page)">
<li
v-if="pageIndex >= 5 && pageIndex < data.meta.last_page - 3"
v-for="(page, index) in floatPages"
:key="index"
class="inline-block p-1"
@click="goToPage(page)"
>
<a
class="page-link"
:class="{
@@ -141,7 +158,8 @@
<a
class="page-link"
:class="{
'bg-light-background dark:bg-4x-dark-foreground dark:text-gray-300': pageIndex === data.meta.last_page - (4 - index),
'bg-light-background dark:bg-4x-dark-foreground dark:text-gray-300':
pageIndex === data.meta.last_page - (4 - index),
}"
>
{{ data.meta.last_page - (4 - index) }}
@@ -149,7 +167,11 @@
</li>
<!--Show last page-->
<li class="inline-block p-1" v-if="pageIndex < data.meta.last_page - 3" @click="goToPage(data.meta.last_page)">
<li
class="inline-block p-1"
v-if="pageIndex < data.meta.last_page - 3"
@click="goToPage(data.meta.last_page)"
>
<a class="page-link">
{{ data.meta.last_page }}
</a>
@@ -169,7 +191,9 @@
</li>
</ul>
<span class="text-xs text-gray-600 dark:text-gray-500"> Showing {{ data.meta.from }} - {{ data.meta.to }} from {{ data.meta.total }} records </span>
<span class="text-xs text-gray-600 dark:text-gray-500">
Showing {{ data.meta.from }} - {{ data.meta.to }} from {{ data.meta.total }} records
</span>
</div>
</div>
</template>
@@ -239,7 +263,14 @@ export default {
if (this.paginator) this.URI = this.URI + '?page=' + page
// Add filder URI if is defined sorting
if (this.filter.field) this.URI = this.URI + (this.paginator ? '&' : '?') + 'sort=' + this.filter.field + '&direction=' + this.filter.sort
if (this.filter.field)
this.URI =
this.URI +
(this.paginator ? '&' : '?') +
'sort=' +
this.filter.field +
'&direction=' +
this.filter.sort
this.isLoading = true

View File

@@ -3,16 +3,30 @@
<!--Item thumbnail-->
<div class="relative w-16">
<!--Member thumbnail for team folders-->
<MemberAvatar v-if="user && canShowAuthor" :size="28" :is-border="true" :member="item.data.relationships.owner" class="absolute right-1.5 -bottom-2 z-10" />
<MemberAvatar
v-if="user && canShowAuthor"
:size="28"
:is-border="true"
:member="item.data.relationships.owner"
class="absolute right-1.5 -bottom-2 z-10"
/>
<!--Emoji Icon-->
<Emoji v-if="item.data.attributes.emoji" :emoji="item.data.attributes.emoji" class="ml-1 scale-110 transform text-5xl" />
<Emoji
v-if="item.data.attributes.emoji"
:emoji="item.data.attributes.emoji"
class="ml-1 scale-110 transform text-5xl"
/>
<!--Folder Icon-->
<FolderIcon v-if="isFolder && !item.data.attributes.emoji" :item="item" />
<!--File Icon-->
<FileIconThumbnail v-if="isFile || isVideo || isAudio || (isImage && !item.data.attributes.thumbnail)" :item="item" class="pr-2" />
<FileIconThumbnail
v-if="isFile || isVideo || isAudio || (isImage && !item.data.attributes.thumbnail)"
:item="item"
class="pr-2"
/>
<!--Image thumbnail-->
<img
@@ -27,7 +41,10 @@
<!--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">
<b
class="mb-0.5 block overflow-hidden text-ellipsis whitespace-nowrap text-sm hover:underline"
style="max-width: 240px"
>
{{ item.data.attributes.name }}
</b>
@@ -39,11 +56,14 @@
</div>
<!--File & Image sub line-->
<small v-if="!isFolder" class="block text-xs text-gray-500"> {{ item.data.attributes.filesize }}, {{ timeStamp }} </small>
<small v-if="!isFolder" class="block text-xs text-gray-500">
{{ item.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 }}
{{ folderItems === 0 ? $t('folder.empty') : $tc('folder.item_counts', folderItems) }},
{{ timeStamp }}
</small>
</div>
</div>
@@ -105,7 +125,9 @@ export default {
)
},
folderItems() {
return this.item.data.attributes.deleted_at ? this.item.data.attributes.trashed_items : this.item.data.attributes.items
return this.item.data.attributes.deleted_at
? this.item.data.attributes.trashed_items
: this.item.data.attributes.items
},
canShowAuthor() {
return !this.isFolder && this.user.data.id !== this.item.data.relationships.owner.data.id

View File

@@ -24,10 +24,30 @@
</span>
<!--Item icon-->
<hard-drive-icon v-if="['public', 'files'].includes(nodes.location)" size="17" class="icon vue-feather" :class="{ 'text-theme dark-text-theme': isSelectedItem }" />
<users-icon v-if="nodes.location === 'team-folders'" size="17" class="icon vue-feather" :class="{ 'text-theme dark-text-theme': isSelectedItem }" />
<user-plus-icon v-if="nodes.location === 'shared-with-me'" size="17" class="icon vue-feather" :class="{ 'text-theme dark-text-theme': isSelectedItem }" />
<folder-icon v-if="!nodes.location" size="17" class="icon vue-feather" :class="{ 'text-theme dark-text-theme': isSelectedItem }" />
<hard-drive-icon
v-if="['public', 'files'].includes(nodes.location)"
size="17"
class="icon vue-feather"
:class="{ 'text-theme dark-text-theme': isSelectedItem }"
/>
<users-icon
v-if="nodes.location === 'team-folders'"
size="17"
class="icon vue-feather"
:class="{ 'text-theme dark-text-theme': isSelectedItem }"
/>
<user-plus-icon
v-if="nodes.location === 'shared-with-me'"
size="17"
class="icon vue-feather"
:class="{ 'text-theme dark-text-theme': isSelectedItem }"
/>
<folder-icon
v-if="!nodes.location"
size="17"
class="icon vue-feather"
:class="{ 'text-theme dark-text-theme': isSelectedItem }"
/>
<!--Item label-->
<b
@@ -40,7 +60,14 @@
</div>
<!--Children-->
<tree-node :disabled-by-id="disabledById" :depth="depth + 1" v-if="isVisible" :nodes="item" v-for="item in nodes.folders" :key="item.id" />
<tree-node
:disabled-by-id="disabledById"
:depth="depth + 1"
v-if="isVisible"
:nodes="item"
v-for="item in nodes.folders"
:key="item.id"
/>
</div>
</template>

View File

@@ -23,11 +23,21 @@
/>
</div>
<folder-icon size="17" class="vue-feather mr-2.5" :class="{ 'text-theme': isSelected }" />
<b class="max-w-1 overflow-hidden text-ellipsis whitespace-nowrap text-xs font-bold" :class="{ 'text-theme': isSelected }">
<b
class="max-w-1 overflow-hidden text-ellipsis whitespace-nowrap text-xs font-bold"
:class="{ 'text-theme': isSelected }"
>
{{ nodes.name }}
</b>
</div>
<tree-node :disabled="disableChildren" :depth="depth + 1" v-if="isVisible" :nodes="item" v-for="item in nodes.folders" :key="item.id" />
<tree-node
:disabled="disableChildren"
:depth="depth + 1"
v-if="isVisible"
:nodes="item"
v-for="item in nodes.folders"
:key="item.id"
/>
</div>
</template>

View File

@@ -1,6 +1,10 @@
<template>
<transition name="vignette">
<div v-if="isVisible" class="vignette bg-dark-background bg-opacity-[0.35] dark:bg-opacity-[0.45]" @click="closePopup"></div>
<div
v-if="isVisible"
class="vignette bg-dark-background bg-opacity-[0.35] dark:bg-opacity-[0.45]"
@click="closePopup"
></div>
</transition>
</template>

View File

@@ -4,7 +4,12 @@
<small class="text-xs font-bold text-gray-400 dark:text-gray-600">
{{ title }}
</small>
<chevron-up-icon v-if="canCollapseWrapper" size="12" class="vue-feather mr-5 transform cursor-pointer text-gray-300" :class="{ 'rotate-180': !isVisible }" />
<chevron-up-icon
v-if="canCollapseWrapper"
size="12"
class="vue-feather mr-5 transform cursor-pointer text-gray-300"
:class="{ 'rotate-180': !isVisible }"
/>
</div>
<slot v-if="isVisible" />

View File

@@ -1,5 +1,8 @@
<template>
<section class="content-sidebar z-10 hidden w-52 flex-none select-none overflow-y-auto bg-light-background pt-6 dark:bg-dark-background lg:block xl:w-56" id="content-sidebar">
<section
class="content-sidebar z-10 hidden w-52 flex-none select-none overflow-y-auto bg-light-background pt-6 dark:bg-dark-background lg:block xl:w-56"
id="content-sidebar"
>
<slot></slot>
</section>
</template>

View File

@@ -1,11 +1,17 @@
<template>
<nav v-if="isVisibleNavigationBars" class="menu-bar z-10 hidden w-16 flex-none select-none bg-light-background pt-7 dark:bg-dark-foreground lg:grid xl:w-20">
<nav
v-if="isVisibleNavigationBars"
class="menu-bar z-10 hidden w-16 flex-none select-none bg-light-background pt-7 dark:bg-dark-foreground lg:grid xl:w-20"
>
<!--Navigation-->
<div v-if="user" class="mb-auto text-center">
<MemberAvatar class="mx-auto inline-block" :size="44" :is-border="false" :member="user" />
<!--Usage-->
<div v-if="config.subscriptionType === 'metered' && user.data.meta.usages" class="mt-1 text-center leading-3">
<div
v-if="config.subscriptionType === 'metered' && user.data.meta.usages"
class="mt-1 text-center leading-3"
>
<b class="text-theme block text-xs font-bold leading-3">
{{ user.data.meta.usages.costEstimate }}
</b>
@@ -24,7 +30,9 @@
:class="[{ 'router-link-active': isSection(item.section) }, item.icon]"
class="mb-1.5 block"
>
<div class="button-icon text-theme inline-block cursor-pointer rounded-xl p-3 hover:bg-light-300 dark:hover:bg-4x-dark-foreground">
<div
class="button-icon text-theme inline-block cursor-pointer rounded-xl p-3 hover:bg-light-300 dark:hover:bg-4x-dark-foreground"
>
<hard-drive-icon v-if="item.icon === 'home'" size="20" />
<settings-icon v-if="item.icon === 'settings'" size="20" />
<user-icon v-if="item.icon === 'user'" size="20" />
@@ -34,7 +42,9 @@
<!--Toggle Dark/Light mode-->
<div @click="$store.dispatch('toggleThemeMode')" :title="$t('dark_mode_toggle')" class="mt-6 block">
<div class="button-icon inline-block cursor-pointer rounded-xl p-3 hover:bg-light-300 dark:hover:bg-4x-dark-foreground">
<div
class="button-icon inline-block cursor-pointer rounded-xl p-3 hover:bg-light-300 dark:hover:bg-4x-dark-foreground"
>
<sun-icon v-if="isDarkMode" size="20" />
<moon-icon v-if="!isDarkMode" size="20" />
</div>
@@ -57,7 +67,16 @@
<script>
import MemberAvatar from '../FilesView/MemberAvatar'
import { mapGetters } from 'vuex'
import { MoonIcon, SunIcon, HardDriveIcon, SettingsIcon, Trash2Icon, UserIcon, PowerIcon, ShareIcon } from 'vue-feather-icons'
import {
MoonIcon,
SunIcon,
HardDriveIcon,
SettingsIcon,
Trash2Icon,
UserIcon,
PowerIcon,
ShareIcon,
} from 'vue-feather-icons'
export default {
name: 'SidebarNavigation',

View File

@@ -1,6 +1,10 @@
<template>
<div class="flex cursor-pointer items-center py-2">
<span class="dark-text-theme rounded-lg bg-light-background py-1 px-2 text-sm font-bold dark:bg-4x-dark-foreground"> {{ keyword }} + {{ $t('space') }} </span>
<span
class="dark-text-theme rounded-lg bg-light-background py-1 px-2 text-sm font-bold dark:bg-4x-dark-foreground"
>
{{ keyword }} + {{ $t('space') }}
</span>
<p class="ml-3 text-sm font-semibold text-gray-500">
{{ description }}
</p>

View File

@@ -1,17 +1,33 @@
<template>
<div v-if="isVisible" @keyup.esc="exitSpotlight" @click.exact.self="exitSpotlight" tabindex="-1" class="fixed z-50 h-full w-full left-0 right-0 bottom-0 top-0 z-50 md:absolute dark:bg-dark-background bg-white md:bg-dark-background dark:md:bg-opacity-[0.45] md:bg-opacity-[0.35]">
<div class="relative z-50 mx-auto w-full overflow-y-auto md:mt-8 md:max-w-xl md:rounded-xl 2xl:mt-20 md:bg-white dark:md:bg-2x-dark-foreground md:shadow-xl">
<div
v-if="isVisible"
@keyup.esc="exitSpotlight"
@click.exact.self="exitSpotlight"
tabindex="-1"
class="fixed left-0 right-0 bottom-0 top-0 z-50 z-50 h-full w-full bg-white dark:bg-dark-background md:absolute md:bg-dark-background md:bg-opacity-[0.35] dark:md:bg-opacity-[0.45]"
>
<div
class="relative z-50 mx-auto w-full overflow-y-auto md:mt-8 md:max-w-xl md:rounded-xl md:bg-white md:shadow-xl dark:md:bg-2x-dark-foreground 2xl:mt-20"
>
<!--Query bar-->
<div class="z-50 mx-auto flex items-center px-5 py-4">
<div class="relative mr-4">
<div v-if="isLoading" class="spinner-icon origin-center translate-y-2.5 scale-50 transform">
<Spinner />
</div>
<search-icon :class="{ 'opacity-0': isLoading }" size="22" class="magnify dark-text-theme text-theme vue-feather" />
<search-icon
:class="{ 'opacity-0': isLoading }"
size="22"
class="magnify dark-text-theme text-theme vue-feather"
/>
</div>
<!--Filter-->
<div v-if="activeFilter" @click="removeFilter" class="mr-3 flex cursor-pointer items-center rounded-lg bg-light-background px-2 py-1 dark:bg-4x-dark-foreground">
<div
v-if="activeFilter"
@click="removeFilter"
class="mr-3 flex cursor-pointer items-center rounded-lg bg-light-background px-2 py-1 dark:bg-4x-dark-foreground"
>
<b class="dark-text-theme -mt-0.5 pr-1.5 text-sm font-bold">
{{ activeFilter }}
</b>
@@ -44,12 +60,21 @@
</div>
<!--Show tips-->
<div v-if="isEmptyQuery && !activeFilter && ! $isThisRoute($route, ['Public'])" class="relative z-50 px-4 pb-4">
<div
v-if="isEmptyQuery && !activeFilter && !$isThisRoute($route, ['Public'])"
class="relative z-50 px-4 pb-4"
>
<CategoryName>
{{ $t('Suggested Filters') }}
</CategoryName>
<FilterSuggestion v-for="filter in filters" :key="filter.slug" :keyword="filter.keyword" :description="filter.description" @click.native="setFilter(filter.slug)" />
<FilterSuggestion
v-for="filter in filters"
:key="filter.slug"
:keyword="filter.keyword"
:description="filter.description"
@click.native="setFilter(filter.slug)"
/>
</div>
<!--Results-->
@@ -68,30 +93,126 @@
'rounded-xl bg-light-background dark:bg-4x-dark-foreground': i === index,
}"
>
<settings-icon v-if="['AppOthers', 'Profile', 'Password'].includes(result.action.value)" size="18" class="vue-feather text-theme" />
<credit-card-icon v-if="result.action.value === 'AppPayments'" size="18" class="vue-feather text-theme" />
<home-icon v-if="result.action.value === 'Files'" size="18" class="vue-feather text-theme" />
<trash2-icon v-if="result.action.value === 'Trash'" size="18" class="vue-feather text-theme" />
<database-icon v-if="['CreateFixedPlan', 'CreateMeteredPlan'].includes(result.action.value)" size="18" class="vue-feather text-theme" />
<user-plus-icon v-if="result.action.value === 'UserCreate'" size="18" class="vue-feather text-theme" />
<users-icon v-if="['TeamFolders', 'Users'].includes(result.action.value)" size="18" class="vue-feather text-theme" />
<user-check-icon v-if="result.action.value === 'SharedWithMe'" size="18" class="vue-feather text-theme" />
<link-icon v-if="result.action.value === 'MySharedItems'" size="18" class="vue-feather text-theme" />
<upload-cloud-icon v-if="result.action.value === 'RecentUploads'" size="18" class="vue-feather text-theme" />
<file-text-icon v-if="['Invoices', 'Invoice'].includes(result.action.value)" size="18" class="vue-feather text-theme" />
<database-icon v-if="result.action.value === 'Plans'" size="18" class="vue-feather text-theme" />
<dollar-sign-icon v-if="['Subscriptions', 'Billing'].includes(result.action.value)" size="18" class="vue-feather text-theme" />
<globe-icon v-if="result.action.value === 'Language'" size="18" class="vue-feather text-theme" />
<monitor-icon v-if="result.action.value === 'Pages'" size="18" class="vue-feather text-theme" />
<box-icon v-if="result.action.value === 'Dashboard'" size="18" class="vue-feather text-theme" />
<hard-drive-icon v-if="result.action.value === 'Storage'" size="18" class="vue-feather text-theme" />
<moon-icon v-if="result.action.value === 'dark-mode'" size="18" class="vue-feather text-theme" />
<maximize2-icon v-if="result.action.value === 'full-screen-mode'" size="18" class="vue-feather text-theme" />
<power-icon v-if="result.action.value === 'log-out'" size="18" class="vue-feather text-theme" />
<trash-icon v-if="result.action.value === 'empty-trash'" size="18" class="vue-feather text-theme" />
<grid-icon v-if="result.action.value === 'toggle-grid-list'" size="18" class="vue-feather text-theme" />
<smile-icon v-if="result.action.value === 'toggle-emoji'" size="18" class="vue-feather text-theme" />
<folder-plus-icon v-if="result.action.value === 'create-team-folder'" size="18" class="vue-feather text-theme" />
<settings-icon
v-if="['AppOthers', 'Profile', 'Password'].includes(result.action.value)"
size="18"
class="vue-feather text-theme"
/>
<credit-card-icon
v-if="result.action.value === 'AppPayments'"
size="18"
class="vue-feather text-theme"
/>
<home-icon
v-if="result.action.value === 'Files'"
size="18"
class="vue-feather text-theme"
/>
<trash2-icon
v-if="result.action.value === 'Trash'"
size="18"
class="vue-feather text-theme"
/>
<database-icon
v-if="['CreateFixedPlan', 'CreateMeteredPlan'].includes(result.action.value)"
size="18"
class="vue-feather text-theme"
/>
<user-plus-icon
v-if="result.action.value === 'UserCreate'"
size="18"
class="vue-feather text-theme"
/>
<users-icon
v-if="['TeamFolders', 'Users'].includes(result.action.value)"
size="18"
class="vue-feather text-theme"
/>
<user-check-icon
v-if="result.action.value === 'SharedWithMe'"
size="18"
class="vue-feather text-theme"
/>
<link-icon
v-if="result.action.value === 'MySharedItems'"
size="18"
class="vue-feather text-theme"
/>
<upload-cloud-icon
v-if="result.action.value === 'RecentUploads'"
size="18"
class="vue-feather text-theme"
/>
<file-text-icon
v-if="['Invoices', 'Invoice'].includes(result.action.value)"
size="18"
class="vue-feather text-theme"
/>
<database-icon
v-if="result.action.value === 'Plans'"
size="18"
class="vue-feather text-theme"
/>
<dollar-sign-icon
v-if="['Subscriptions', 'Billing'].includes(result.action.value)"
size="18"
class="vue-feather text-theme"
/>
<globe-icon
v-if="result.action.value === 'Language'"
size="18"
class="vue-feather text-theme"
/>
<monitor-icon
v-if="result.action.value === 'Pages'"
size="18"
class="vue-feather text-theme"
/>
<box-icon
v-if="result.action.value === 'Dashboard'"
size="18"
class="vue-feather text-theme"
/>
<hard-drive-icon
v-if="result.action.value === 'Storage'"
size="18"
class="vue-feather text-theme"
/>
<moon-icon
v-if="result.action.value === 'dark-mode'"
size="18"
class="vue-feather text-theme"
/>
<maximize2-icon
v-if="result.action.value === 'full-screen-mode'"
size="18"
class="vue-feather text-theme"
/>
<power-icon
v-if="result.action.value === 'log-out'"
size="18"
class="vue-feather text-theme"
/>
<trash-icon
v-if="result.action.value === 'empty-trash'"
size="18"
class="vue-feather text-theme"
/>
<grid-icon
v-if="result.action.value === 'toggle-grid-list'"
size="18"
class="vue-feather text-theme"
/>
<smile-icon
v-if="result.action.value === 'toggle-emoji'"
size="18"
class="vue-feather text-theme"
/>
<folder-plus-icon
v-if="result.action.value === 'create-team-folder'"
size="18"
class="vue-feather text-theme"
/>
<b class="ml-3.5 text-sm font-bold">
{{ result.title }}
@@ -122,7 +243,10 @@
>
<MemberAvatar :is-border="false" :size="44" :member="result" />
<div class="ml-3">
<b class="max-w-1 block overflow-hidden text-ellipsis whitespace-nowrap text-sm font-bold" style="max-width: 155px">
<b
class="max-w-1 block overflow-hidden text-ellipsis whitespace-nowrap text-sm font-bold"
style="max-width: 155px"
>
{{ result.data.attributes.name }}
</b>
<span class="block text-xs text-gray-600 dark:text-gray-500">
@@ -145,12 +269,17 @@
<!--Keyboard shortcut hint-->
<div v-if="!$isMobile()" class="absolute right-4 top-1/2 -translate-y-1/2 transform">
<span class="text-xs text-gray-400">{{ i + actions.length === 0 ? '↵' : metaKeyIcon + (i + actions.length) }}</span>
<span class="text-xs text-gray-400">{{
i + actions.length === 0 ? '↵' : metaKeyIcon + (i + actions.length)
}}</span>
</div>
</div>
<!--Show Empty message-->
<span v-if="results.length === 0 && actions.length === 0" class="p-2.5 text-sm text-gray-700 dark:text-gray-400">
<span
v-if="results.length === 0 && actions.length === 0"
class="p-2.5 text-sm text-gray-700 dark:text-gray-400"
>
{{ $t('messages.nothing_was_found') }}
</span>
</div>
@@ -172,7 +301,7 @@ import KeyboardHints from './KeyboardHints'
import axios from 'axios'
import { debounce } from 'lodash'
import {
FolderPlusIcon,
FolderPlusIcon,
SmileIcon,
BoxIcon,
CreditCardIcon,
@@ -203,7 +332,7 @@ import { mapGetters } from 'vuex'
export default {
name: 'Spotlight',
components: {
FolderPlusIcon,
FolderPlusIcon,
SmileIcon,
KeyboardHints,
CreditCardIcon,
@@ -381,31 +510,31 @@ export default {
value: 'Billing',
},
},
{
title: this.$t('Empty Your Trash'),
action: {
type: 'function',
value: 'empty-trash',
},
},
{
title: this.$t('Log Out'),
action: {
type: 'function',
value: 'log-out',
},
},
{
title: this.$t('Empty Your Trash'),
action: {
type: 'function',
value: 'empty-trash',
},
},
{
title: this.$t('Log Out'),
action: {
type: 'function',
value: 'log-out',
},
},
]
let createList = [
{
title: this.$t('Create Team Folder'),
action: {
type: 'function',
value: 'create-team-folder',
},
},
]
let createList = [
{
title: this.$t('Create Team Folder'),
action: {
type: 'function',
value: 'create-team-folder',
},
},
]
let functionList = [
{
@@ -442,12 +571,12 @@ export default {
})
}
// Return commands for public page
if (this.$isThisRoute(this.$route, ['Public'])) {
return [].concat.apply([], [functionList])
}
// Return commands for public page
if (this.$isThisRoute(this.$route, ['Public'])) {
return [].concat.apply([], [functionList])
}
// Return commands for logged admin
// Return commands for logged admin
if (this.user.data.attributes.role === 'admin') {
// Available only for fixed subscription
if (this.config.subscriptionType === 'fixed') {
@@ -461,7 +590,10 @@ export default {
}
// Available only when is metered billing and plan doesnt exist or when is fixed billing
if ((this.config.subscriptionType === 'metered' && !this.config.isCreatedMeteredPlan) || this.config.subscriptionType === 'fixed') {
if (
(this.config.subscriptionType === 'metered' && !this.config.isCreatedMeteredPlan) ||
this.config.subscriptionType === 'fixed'
) {
adminActions.push({
title: this.$t('Create Plan'),
action: {
@@ -471,11 +603,14 @@ export default {
})
}
return [].concat.apply([], [functionList, createList, userSettings, fileLocations, adminLocations, adminActions])
return [].concat.apply(
[],
[functionList, createList, userSettings, fileLocations, adminLocations, adminActions]
)
}
// Return commands for logged user
if (this.user.data.attributes.role === 'user') {
// Return commands for logged user
if (this.user.data.attributes.role === 'user') {
return [].concat.apply([], [functionList, createList, userSettings, fileLocations])
}
},
@@ -533,7 +668,9 @@ export default {
// Browse actions
if (!this.activeFilter) {
this.actions = this.actionList.filter((el) => el.title.toLowerCase().indexOf(formattedQuery) > -1).slice(0, 3)
this.actions = this.actionList
.filter((el) => el.title.toLowerCase().indexOf(formattedQuery) > -1)
.slice(0, 3)
}
this.findResult(formattedQuery)
@@ -623,16 +760,15 @@ export default {
openItem(file) {
// Show folder
if (file.data.type === 'folder') {
if (this.$isThisRoute(this.$route, ['Public'])) {
this.$router.push({
name: 'Public',
params: {
token: this.sharedDetail.data.attributes.token,
id: file.data.id,
},
})
} else if (file.data.attributes.isTeamFolder) {
if (this.$isThisRoute(this.$route, ['Public'])) {
this.$router.push({
name: 'Public',
params: {
token: this.sharedDetail.data.attributes.token,
id: file.data.id,
},
})
} else if (file.data.attributes.isTeamFolder) {
if (file.data.relationships.owner.data.id === this.user.data.id) {
this.$router.push({
name: 'TeamFolders',
@@ -657,7 +793,10 @@ export default {
events.$emit('file-preview:show')
} else {
this.$downloadFile(file.data.attributes.file_url, file.data.attributes.name + '.' + file.data.attributes.mimetype)
this.$downloadFile(
file.data.attributes.file_url,
file.data.attributes.name + '.' + file.data.attributes.mimetype
)
}
}
@@ -671,8 +810,8 @@ export default {
// Get route
let route = this.$store.getters.sharedDetail
? `/api/browse/search/${this.$router.currentRoute.params.token}`
: '/api/browse/search'
? `/api/browse/search/${this.$router.currentRoute.params.token}`
: '/api/browse/search'
axios
.get(`${route}?filter=${this.activeFilter}`, {

View File

@@ -9,7 +9,10 @@
<div v-if="row.data.relationships.user" class="flex items-center">
<MemberAvatar :is-border="false" :size="36" :member="row.data.relationships.user" />
<div class="ml-3 pr-10">
<b class="max-w-1 block overflow-hidden text-ellipsis whitespace-nowrap text-sm font-bold" style="max-width: 155px">
<b
class="max-w-1 block overflow-hidden text-ellipsis whitespace-nowrap text-sm font-bold"
style="max-width: 155px"
>
{{ row.data.relationships.user.data.attributes.name }}
</b>
<span class="block text-xs text-gray-600 dark:text-gray-500">
@@ -38,7 +41,11 @@
</td>
<td class="px-3 md:px-1">
<div class="w-28">
<img class="inline-block max-h-5" :src="$getPaymentLogo(row.data.attributes.driver)" :alt="row.data.attributes.driver" />
<img
class="inline-block max-h-5"
:src="$getPaymentLogo(row.data.attributes.driver)"
:alt="row.data.attributes.driver"
/>
</div>
</td>
<td class="pl-3 text-right md:pl-1">

View File

@@ -9,7 +9,10 @@
<div v-if="row.data.relationships.user" class="flex items-center">
<MemberAvatar :is-border="false" :size="36" :member="row.data.relationships.user" />
<div class="ml-3 pr-10">
<b class="max-w-1 block overflow-hidden text-ellipsis whitespace-nowrap text-sm font-bold" style="max-width: 155px">
<b
class="max-w-1 block overflow-hidden text-ellipsis whitespace-nowrap text-sm font-bold"
style="max-width: 155px"
>
{{ row.data.relationships.user.data.attributes.name }}
</b>
<span class="block text-xs text-gray-600 dark:text-gray-500">
@@ -43,7 +46,11 @@
</td>
<td class="px-3 md:px-1">
<div class="w-28">
<img class="inline-block max-h-5" :src="$getPaymentLogo(row.data.attributes.driver)" :alt="row.data.attributes.driver" />
<img
class="inline-block max-h-5"
:src="$getPaymentLogo(row.data.attributes.driver)"
:alt="row.data.attributes.driver"
/>
</div>
</td>
<td class="pl-3 text-right md:pl-1">

View File

@@ -1,5 +1,7 @@
<template>
<div class="flex items-center justify-between rounded-lg bg-light-background py-3 px-2 dark:bg-2x-dark-foreground md:px-4">
<div
class="flex items-center justify-between rounded-lg bg-light-background py-3 px-2 dark:bg-2x-dark-foreground md:px-4"
>
<div class="flex items-center">
<img :src="`/assets/gateways/${card.data.attributes.brand}.svg`" alt="" class="mr-3 h-5 rounded" />
<b class="whitespace-nowrap text-sm font-bold capitalize leading-none">
@@ -26,7 +28,9 @@ export default {
deleteCreditCard(id) {
events.$emit('confirm:open', {
title: this.$t('Are you sure you want to delete your credit card?'),
message: this.$t('We will no longer settle your payments automatically and you will have to fund your account for the next payments.'),
message: this.$t(
'We will no longer settle your payments automatically and you will have to fund your account for the next payments.'
),
action: {
id: id,
operation: 'delete-credit-card',

View File

@@ -10,7 +10,9 @@
<b class="flex-1 pl-4 text-left text-lg">
{{ plan.data.attributes.name }}
</b>
<span class="text-theme bg-theme-100 ml-9 inline-block whitespace-nowrap rounded-xl py-1 px-2 text-sm font-extrabold">
<span
class="text-theme bg-theme-100 ml-9 inline-block whitespace-nowrap rounded-xl py-1 px-2 text-sm font-extrabold"
>
{{ plan.data.attributes.price }} /
{{ $t(`interval.${plan.data.attributes.interval}`) }}
</span>

View File

@@ -6,11 +6,19 @@
<div v-if="isPaymentOptionPage">
<PopupContent>
<!--Stripe implementation-->
<PaymentMethod v-if="config.isStripe" driver="stripe" :description="$t('Pay by your credit card or Apple Pay')">
<PaymentMethod
v-if="config.isStripe"
driver="stripe"
:description="$t('Pay by your credit card or Apple Pay')"
>
<div v-if="stripe.isGettingCheckoutLink" class="translate-y-3 scale-50 transform">
<Spinner />
</div>
<span @click="payByStripe" :class="{ 'opacity-0': stripe.isGettingCheckoutLink }" class="text-theme cursor-pointer text-sm font-bold">
<span
@click="payByStripe"
:class="{ 'opacity-0': stripe.isGettingCheckoutLink }"
class="text-theme cursor-pointer text-sm font-bold"
>
{{ $t('Select') }}
</span>
</PaymentMethod>
@@ -22,11 +30,19 @@
'mb-2 rounded-xl bg-light-background px-4 dark:bg-2x-dark-foreground': paypal.isMethodsLoaded,
}"
>
<PaymentMethod @click.native="pickedPaymentMethod('paypal')" driver="paypal" :description="$t('Available PayPal Credit, Debit or Credit Card.')">
<PaymentMethod
@click.native="pickedPaymentMethod('paypal')"
driver="paypal"
:description="$t('Available PayPal Credit, Debit or Credit Card.')"
>
<div v-if="paypal.isMethodLoading" class="translate-y-3 scale-50 transform">
<Spinner />
</div>
<span v-if="!paypal.isMethodsLoaded" :class="{ 'opacity-0': paypal.isMethodLoading }" class="text-theme cursor-pointer text-sm font-bold">
<span
v-if="!paypal.isMethodsLoaded"
:class="{ 'opacity-0': paypal.isMethodLoading }"
class="text-theme cursor-pointer text-sm font-bold"
>
{{ $t('Select') }}
</span>
</PaymentMethod>
@@ -36,7 +52,11 @@
</div>
<!--Paystack implementation-->
<PaymentMethod v-if="config.isPaystack" driver="paystack" :description="$t('Available Bank Account, USSD, Mobile Money, Apple Pay')">
<PaymentMethod
v-if="config.isPaystack"
driver="paystack"
:description="$t('Available Bank Account, USSD, Mobile Money, Apple Pay')"
>
<paystack
v-if="user && config"
:channels="['bank', 'ussd', 'qr', 'mobile_money', 'bank_transfer']"
@@ -67,18 +87,24 @@
<!--Select Payment Plans-->
<div v-if="!isPaymentOptionPage">
<PopupContent v-if="plans">
<InfoBox v-if="plans.data.length === 0" class="!mb-0">
<p>There isn't any plan yet.</p>
</InfoBox>
<InfoBox v-if="plans.data.length === 0" class="!mb-0">
<p>There isn't any plan yet.</p>
</InfoBox>
<!--Toggle yearly billing-->
<div v-if="hasYearlyPlans.length > 0" class="mb-2 px-5 text-right">
<label :class="{ 'text-gray-400': !isSelectedYearlyPlans }" class="cursor-pointer text-xs font-bold">
<label
:class="{ 'text-gray-400': !isSelectedYearlyPlans }"
class="cursor-pointer text-xs font-bold"
>
{{ $t('Billed Annually') }}
</label>
<div class="relative inline-block w-12 select-none align-middle">
<SwitchInput class="scale-75 transform" v-model="isSelectedYearlyPlans" :state="isSelectedYearlyPlans" />
<SwitchInput
class="scale-75 transform"
v-model="isSelectedYearlyPlans"
:state="isSelectedYearlyPlans"
/>
</div>
</div>
@@ -88,7 +114,9 @@
v-for="(plan, i) in plans.data"
:plan="plan"
:key="plan.data.id"
v-if="plan.data.attributes.interval === intervalPlanType && userSubscribedPlanId !== plan.data.id"
v-if="
plan.data.attributes.interval === intervalPlanType && userSubscribedPlanId !== plan.data.id
"
:is-selected="selectedPlan && selectedPlan.data.id === plan.data.id"
@click.native="selectPlan(plan)"
/>
@@ -97,8 +125,16 @@
<!--Actions-->
<PopupActions>
<ButtonBase class="w-full" @click.native="$closePopup()" button-style="secondary">{{ $t('popup_move_item.cancel') }} </ButtonBase>
<ButtonBase class="w-full" v-if="plans.data.length !== 0" :button-style="buttonStyle" @click.native="isPaymentOptionPage = true">{{ $t('Upgrade Account') }} </ButtonBase>
<ButtonBase class="w-full" @click.native="$closePopup()" button-style="secondary"
>{{ $t('popup_move_item.cancel') }}
</ButtonBase>
<ButtonBase
class="w-full"
v-if="plans.data.length !== 0"
:button-style="buttonStyle"
@click.native="isPaymentOptionPage = true"
>{{ $t('Upgrade Account') }}
</ButtonBase>
</PopupActions>
</div>
</PopupWrapper>
@@ -119,12 +155,12 @@ import { mapGetters } from 'vuex'
import { events } from '../../bus'
import axios from 'axios'
import Spinner from '../FilesView/Spinner'
import InfoBox from "../Others/Forms/InfoBox";
import InfoBox from '../Others/Forms/InfoBox'
export default {
name: 'SelectPlanSubscriptionPopup',
components: {
InfoBox,
InfoBox,
Spinner,
PaymentMethod,
paystack,
@@ -150,7 +186,11 @@ export default {
return this.selectedPlan ? 'theme' : 'secondary'
},
userSubscribedPlanId() {
return this.user && this.user.data.relationships.subscription && this.user.data.relationships.subscription.data.relationships.plan.data.id
return (
this.user &&
this.user.data.relationships.subscription &&
this.user.data.relationships.subscription.data.relationships.plan.data.id
)
},
hasYearlyPlans() {
return this.plans.data.filter((plan) => plan.data.attributes.interval === 'year')

View File

@@ -9,9 +9,27 @@
</b>
<!-- Make payment form -->
<ValidationObserver ref="fundAccount" @submit.prevent="makePayment" v-slot="{ invalid }" tag="form" class="mt-6">
<ValidationProvider tag="div" v-slot="{ errors }" mode="passive" name="Amount" :rules="`required|min_value:${user.data.meta.totalDebt.amount}`">
<AppInputText :description="$t('The amount will be increased as soon as we register your charge from payment gateway.')" :error="errors[0]" :is-last="true">
<ValidationObserver
ref="fundAccount"
@submit.prevent="makePayment"
v-slot="{ invalid }"
tag="form"
class="mt-6"
>
<ValidationProvider
tag="div"
v-slot="{ errors }"
mode="passive"
name="Amount"
:rules="`required|min_value:${user.data.meta.totalDebt.amount}`"
>
<AppInputText
:description="
$t('The amount will be increased as soon as we register your charge from payment gateway.')
"
:error="errors[0]"
:is-last="true"
>
<div class="space-y-4 sm:flex sm:space-x-4 sm:space-y-0">
<input
v-model="chargeAmount"

View File

@@ -13,7 +13,12 @@
size="12"
class="vue-feather ml-2 -translate-y-0.5 transform cursor-pointer"
/>
<trash2-icon v-if="showUpdateBillingAlertForm" @click="deleteBillingAlert" size="12" class="vue-feather ml-2 -translate-y-0.5 transform cursor-pointer" />
<trash2-icon
v-if="showUpdateBillingAlertForm"
@click="deleteBillingAlert"
size="12"
class="vue-feather ml-2 -translate-y-0.5 transform cursor-pointer"
/>
</b>
<b class="block text-sm text-gray-400">
@@ -21,9 +26,24 @@
</b>
</div>
<ValidationObserver v-if="showUpdateBillingAlertForm" ref="updatebillingAlertForm" @submit.prevent="updateBillingAlert" v-slot="{ invalid }" tag="form" class="mt-6">
<ValidationObserver
v-if="showUpdateBillingAlertForm"
ref="updatebillingAlertForm"
@submit.prevent="updateBillingAlert"
v-slot="{ invalid }"
tag="form"
class="mt-6"
>
<ValidationProvider tag="div" v-slot="{ errors }" mode="passive" name="Billing Alert" rules="required">
<AppInputText :description="$t('You will receive an email whenever your monthly balance reaches the specified amount above.')" :error="errors[0]" :is-last="true">
<AppInputText
:description="
$t(
'You will receive an email whenever your monthly balance reaches the specified amount above.'
)
"
:error="errors[0]"
:is-last="true"
>
<div class="space-y-4 sm:flex sm:space-x-4 sm:space-y-0">
<input
v-model="billingAlertAmount"
@@ -34,7 +54,13 @@
class="focus-border-theme input-dark"
:class="{ 'border-red': errors[0] }"
/>
<ButtonBase :loadint="isSendingBillingAlert" :disabled="isSendingBillingAlert" type="submit" button-style="theme" class="w-full sm:w-auto">
<ButtonBase
:loadint="isSendingBillingAlert"
:disabled="isSendingBillingAlert"
type="submit"
button-style="theme"
class="w-full sm:w-auto"
>
{{ $t('Update Alert') }}
</ButtonBase>
</div>
@@ -42,9 +68,24 @@
</ValidationProvider>
</ValidationObserver>
<ValidationObserver v-if="!user.data.relationships.alert" ref="billingAlertForm" @submit.prevent="setBillingAlert" v-slot="{ invalid }" tag="form" class="mt-6">
<ValidationObserver
v-if="!user.data.relationships.alert"
ref="billingAlertForm"
@submit.prevent="setBillingAlert"
v-slot="{ invalid }"
tag="form"
class="mt-6"
>
<ValidationProvider tag="div" v-slot="{ errors }" mode="passive" name="Billing Alert" rules="required">
<AppInputText :description="$t('You will receive an email whenever your monthly balance reaches the specified amount above.')" :error="errors[0]" :is-last="true">
<AppInputText
:description="
$t(
'You will receive an email whenever your monthly balance reaches the specified amount above.'
)
"
:error="errors[0]"
:is-last="true"
>
<div class="space-y-4 sm:flex sm:space-x-4 sm:space-y-0">
<input
v-model="billingAlertAmount"
@@ -55,7 +96,13 @@
class="focus-border-theme input-dark"
:class="{ 'border-red': errors[0] }"
/>
<ButtonBase :loadint="isSendingBillingAlert" :disabled="isSendingBillingAlert" type="submit" button-style="theme" class="w-full sm:w-auto">
<ButtonBase
:loadint="isSendingBillingAlert"
:disabled="isSendingBillingAlert"
type="submit"
button-style="theme"
class="w-full sm:w-auto"
>
{{ $t('Set Alert') }}
</ButtonBase>
</div>
@@ -161,7 +208,9 @@ export default {
deleteBillingAlert() {
events.$emit('confirm:open', {
title: this.$t('Are you sure you want to delete your alert?'),
message: this.$t('You will no longer receive any notifications that your billing limit has been exceeded.'),
message: this.$t(
'You will no longer receive any notifications that your billing limit has been exceeded.'
),
action: {
id: this.user.data.relationships.alert.data.id,
operation: 'delete-billing-alert',

View File

@@ -7,14 +7,27 @@
<AppInputButton
v-if="subscription.attributes.status !== 'cancelled'"
:title="$t('Cancel Subscription')"
:description="$t('You can cancel your subscription now. You\'ll continue to have access to the features you\'ve paid for until the end of your billing cycle.')"
:description="
$t(
'You can cancel your subscription now. You\'ll continue to have access to the features you\'ve paid for until the end of your billing cycle.'
)
"
>
<ButtonBase @click.native="cancelSubscriptionConfirmation" :loading="isCancelling" class="w-full sm:w-auto" button-style="secondary">
<ButtonBase
@click.native="cancelSubscriptionConfirmation"
:loading="isCancelling"
class="w-full sm:w-auto"
button-style="secondary"
>
{{ $t('Cancel Now') }}
</ButtonBase>
</AppInputButton>
<AppInputButton :title="$t('Upgrade or Downgrade Plan')" :description="$t('You can upgrade your plan at any time you want.')" :is-last="true">
<AppInputButton
:title="$t('Upgrade or Downgrade Plan')"
:description="$t('You can upgrade your plan at any time you want.')"
:is-last="true"
>
<ButtonBase @click.native="$openUpgradeOptions" class="w-full sm:w-auto" button-style="secondary">
{{ $t('Change Plan') }}
</ButtonBase>
@@ -57,7 +70,9 @@ export default {
cancelSubscriptionConfirmation() {
events.$emit('confirm:open', {
title: this.$t('Are you sure you want to cancel subscription?'),
message: this.$t("You'll continue to have access to the features you've paid for until the end of your billing cycle."),
message: this.$t(
"You'll continue to have access to the features you've paid for until the end of your billing cycle."
),
action: {
operation: 'cancel-subscription',
},

View File

@@ -12,7 +12,13 @@
{{ $t('Upgrade your account to get more.') }}
</b>
<ButtonBase v-if="$store.getters.config.allowed_payments" @click.native="$openUpgradeOptions" type="submit" button-style="theme" class="mt-4 w-full">
<ButtonBase
v-if="$store.getters.config.allowed_payments"
@click.native="$openUpgradeOptions"
type="submit"
button-style="theme"
class="mt-4 w-full"
>
{{ $t('Upgrade Your Account') }}
</ButtonBase>
</div>

View File

@@ -1,13 +1,22 @@
<template>
<div v-if="user.data.relationships.failedPayments && user.data.relationships.failedPayments.data.length > 0" class="card shadow-card">
<div
v-if="user.data.relationships.failedPayments && user.data.relationships.failedPayments.data.length > 0"
class="card shadow-card"
>
<FormLabel icon="frown">
{{ $t('Failed Payments') }}
</FormLabel>
<b class="-mt-3 mb-0.5 block text-2xl font-extrabold sm:text-3xl"> -{{ user.data.meta.totalDebt.formatted }} </b>
<b class="-mt-3 mb-0.5 block text-2xl font-extrabold sm:text-3xl">
-{{ user.data.meta.totalDebt.formatted }}
</b>
<b class="mb-3 mb-5 block text-sm text-gray-400">
{{ $t("We are unable to charge your usage. Please register new credit card or fund your account with sufficient amount and we'll give it another try!") }}
{{
$t(
"We are unable to charge your usage. Please register new credit card or fund your account with sufficient amount and we'll give it another try!"
)
}}
</b>
<!--Failed Payments-->

Some files were not shown because too many files have changed in this diff Show More