mirror of
https://github.com/VueFileManager/vuefilemanager.git
synced 2026-04-18 16:22:14 +00:00
vue components refactoring
This commit is contained in:
127
resources/js/components/Popups/Alert.vue
Normal file
127
resources/js/components/Popups/Alert.vue
Normal file
@@ -0,0 +1,127 @@
|
||||
<template>
|
||||
<transition name="popup">
|
||||
<div
|
||||
v-if="isVisibleWrapper"
|
||||
@click.self="closePopup"
|
||||
class="fixed top-0 left-0 right-0 bottom-0 z-50 grid h-full overflow-y-auto p-10"
|
||||
>
|
||||
<div class="fixed top-0 bottom-0 left-0 right-0 z-10 m-auto w-full bg-white shadow-xl dark:bg-dark-foreground md:relative md:w-[490px] md:rounded-xl">
|
||||
<div class="flex h-full -translate-y-7 transform items-center justify-center px-8 text-center md:translate-y-0">
|
||||
<div>
|
||||
<img src="https://twemoji.maxcdn.com/v/13.1.0/svg/1f627.svg" alt="" class="mx-auto mb-4 w-20 md:mt-6 min-h-[80px]" />
|
||||
|
||||
<h1 v-if="title" class="mb-2 text-2xl font-bold">
|
||||
{{ title }}
|
||||
</h1>
|
||||
<p v-if="message" class="mb-4 text-sm overflow-anywhere">
|
||||
{{ message }}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<PopupActions>
|
||||
<ButtonBase @click.native="closePopup" :button-style="buttonStyle" class="w-full">
|
||||
{{ button }}
|
||||
</ButtonBase>
|
||||
</PopupActions>
|
||||
</div>
|
||||
</div>
|
||||
</transition>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import ButtonBase from '../UI/Buttons/ButtonBase'
|
||||
import { events } from '../../bus'
|
||||
import PopupActions from "./Components/PopupActions";
|
||||
|
||||
export default {
|
||||
name: 'AlertPopup',
|
||||
components: {
|
||||
PopupActions,
|
||||
ButtonBase,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
isVisibleWrapper: false,
|
||||
buttonStyle: undefined,
|
||||
message: undefined,
|
||||
title: undefined,
|
||||
button: undefined,
|
||||
emoji: undefined,
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
closePopup() {
|
||||
events.$emit('popup:close')
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
// Show alert
|
||||
events.$on('alert:open', (args) => {
|
||||
this.isVisibleWrapper = true
|
||||
|
||||
this.title = args.title || undefined
|
||||
this.message = args.message || undefined
|
||||
|
||||
this.button = this.$te('alerts.error_confirm') ? this.$t('alerts.error_confirm') : 'That’s horrible!'
|
||||
this.emoji = '😢😢😢'
|
||||
this.buttonStyle = 'danger'
|
||||
|
||||
if (args.emoji) {
|
||||
this.emoji = args.emoji
|
||||
}
|
||||
|
||||
if (args.buttonStyle) {
|
||||
this.buttonStyle = args.buttonStyle
|
||||
}
|
||||
|
||||
if (args.button) {
|
||||
this.button = args.button
|
||||
}
|
||||
})
|
||||
|
||||
// Show alert
|
||||
events.$on('success:open', (args) => {
|
||||
this.isVisibleWrapper = true
|
||||
|
||||
this.title = args.title
|
||||
this.message = args.message
|
||||
|
||||
this.button = this.$t('alerts.success_confirm')
|
||||
this.emoji = '🥳🥳🥳'
|
||||
this.buttonStyle = 'theme'
|
||||
|
||||
if (args.emoji) {
|
||||
this.emoji = args.emoji
|
||||
}
|
||||
})
|
||||
|
||||
// Close popup
|
||||
events.$on('popup:close', () => {
|
||||
this.isVisibleWrapper = false
|
||||
})
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
|
||||
// Animations
|
||||
.popup-enter-active {
|
||||
animation: popup-in 0.35s 0.15s ease both;
|
||||
}
|
||||
|
||||
.popup-leave-active {
|
||||
animation: popup-in 0.15s ease reverse;
|
||||
}
|
||||
|
||||
@keyframes popup-in {
|
||||
0% {
|
||||
opacity: 0;
|
||||
transform: scale(0.7);
|
||||
}
|
||||
100% {
|
||||
opacity: 1;
|
||||
transform: scale(1);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
11
resources/js/components/Popups/Components/PopupActions.vue
Normal file
11
resources/js/components/Popups/Components/PopupActions.vue
Normal file
@@ -0,0 +1,11 @@
|
||||
<template>
|
||||
<div class="absolute bottom-0 left-0 right-0 flex items-center space-x-4 px-6 py-4 pb-6 md:relative">
|
||||
<slot />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'PopupActions',
|
||||
}
|
||||
</script>
|
||||
15
resources/js/components/Popups/Components/PopupContent.vue
Normal file
15
resources/js/components/Popups/Components/PopupContent.vue
Normal file
@@ -0,0 +1,15 @@
|
||||
<template>
|
||||
<div
|
||||
:class="type"
|
||||
class="absolute top-16 bottom-24 left-0 right-0 h-auto overflow-auto px-6 md:relative md:top-0 md:bottom-0"
|
||||
>
|
||||
<slot />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'PopupContent',
|
||||
props: ['type'],
|
||||
}
|
||||
</script>
|
||||
64
resources/js/components/Popups/Components/PopupHeader.vue
Normal file
64
resources/js/components/Popups/Components/PopupHeader.vue
Normal file
@@ -0,0 +1,64 @@
|
||||
<template>
|
||||
<div class="flex items-center justify-between px-6 pt-6 pb-6">
|
||||
<div class="flex items-center">
|
||||
<div class="mr-3">
|
||||
<upload-cloud-icon v-if="icon === 'upload'" size="18" class="vue-feather text-theme" />
|
||||
<corner-down-right-icon v-if="icon === 'move'" size="18" class="vue-feather text-theme" />
|
||||
<share-icon v-if="icon === 'share'" size="18" class="vue-feather text-theme" />
|
||||
<edit2-icon v-if="icon === 'edit'" size="18" class="vue-feather text-theme" />
|
||||
<key-icon v-if="icon === 'key'" size="18" class="vue-feather text-theme" />
|
||||
<users-icon v-if="icon === 'users'" size="18" class="vue-feather text-theme" />
|
||||
<user-plus-icon v-if="icon === 'user-plus'" size="18" class="vue-feather text-theme" />
|
||||
<credit-card-icon v-if="icon === 'credit-card'" size="18" class="vue-feather text-theme" />
|
||||
<bell-icon v-if="icon === 'bell'" size="18" class="vue-feather text-theme" />
|
||||
</div>
|
||||
|
||||
<b class="text-base font-bold">
|
||||
{{ title }}
|
||||
</b>
|
||||
</div>
|
||||
<div @click="closePopup" class="-m-3 cursor-pointer p-3">
|
||||
<x-icon size="14" class="hover-text-theme vue-feather" />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {
|
||||
BellIcon,
|
||||
UploadCloudIcon,
|
||||
CreditCardIcon,
|
||||
KeyIcon,
|
||||
UserPlusIcon,
|
||||
CornerDownRightIcon,
|
||||
LinkIcon,
|
||||
XIcon,
|
||||
Edit2Icon,
|
||||
ShareIcon,
|
||||
UsersIcon,
|
||||
} from 'vue-feather-icons'
|
||||
import { events } from '../../../bus'
|
||||
|
||||
export default {
|
||||
name: 'PopupHeader',
|
||||
props: ['title', 'icon'],
|
||||
components: {
|
||||
BellIcon,
|
||||
UploadCloudIcon,
|
||||
CornerDownRightIcon,
|
||||
CreditCardIcon,
|
||||
UserPlusIcon,
|
||||
UsersIcon,
|
||||
ShareIcon,
|
||||
Edit2Icon,
|
||||
LinkIcon,
|
||||
KeyIcon,
|
||||
XIcon,
|
||||
},
|
||||
methods: {
|
||||
closePopup() {
|
||||
events.$emit('popup:close')
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
89
resources/js/components/Popups/Components/PopupWrapper.vue
Normal file
89
resources/js/components/Popups/Components/PopupWrapper.vue
Normal file
@@ -0,0 +1,89 @@
|
||||
<template>
|
||||
<transition name="popup">
|
||||
<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-dark-foreground md:relative md:w-[490px] md:rounded-xl"
|
||||
>
|
||||
<slot />
|
||||
</div>
|
||||
</div>
|
||||
</transition>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { events } from '../../../bus'
|
||||
|
||||
export default {
|
||||
name: 'PopupWrapper',
|
||||
props: ['name'],
|
||||
data() {
|
||||
return {
|
||||
isVisibleWrapper: false,
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
closePopup() {
|
||||
events.$emit('popup:close')
|
||||
},
|
||||
},
|
||||
created() {
|
||||
// Open called popup
|
||||
events.$on('popup:open', ({ name }) => {
|
||||
if (this.name === name) this.isVisibleWrapper = true
|
||||
|
||||
if (this.name !== name) this.isVisibleWrapper = false
|
||||
})
|
||||
|
||||
// Open called popup
|
||||
events.$on('confirm:open', ({ name }) => {
|
||||
if (this.name === name) this.isVisibleWrapper = true
|
||||
})
|
||||
|
||||
// Close popup
|
||||
events.$on('popup:close', () => (this.isVisibleWrapper = false))
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.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;
|
||||
}
|
||||
|
||||
@keyframes popup-slide-in {
|
||||
0% {
|
||||
opacity: 0;
|
||||
transform: translateY(100px);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
@keyframes popup-slide-in {
|
||||
0% {
|
||||
transform: translateY(100%);
|
||||
}
|
||||
100% {
|
||||
transform: translateY(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
77
resources/js/components/Popups/ConfirmPopup.vue
Normal file
77
resources/js/components/Popups/ConfirmPopup.vue
Normal file
@@ -0,0 +1,77 @@
|
||||
<template>
|
||||
<PopupWrapper>
|
||||
<div class="flex h-full -translate-y-7 transform items-center justify-center px-8 text-center md:translate-y-0">
|
||||
<div>
|
||||
<img src="https://twemoji.maxcdn.com/v/13.1.0/svg/1f914.svg" alt="" class="mx-auto mb-4 w-20 md:mt-6 min-h-[80px]" />
|
||||
|
||||
<h1 v-if="title" class="mb-2 text-2xl font-bold">
|
||||
{{ title }}
|
||||
</h1>
|
||||
<p v-if="message" class="mb-4 text-sm">
|
||||
{{ message }}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<PopupActions>
|
||||
<ButtonBase @click.native="closePopup" button-style="secondary" class="w-full"
|
||||
>{{ $t('cancel') }}
|
||||
</ButtonBase>
|
||||
<ButtonBase @click.native="confirm" :button-style="buttonColor" class="w-full"
|
||||
>{{ $t('yes_iam_sure') }}
|
||||
</ButtonBase>
|
||||
</PopupActions>
|
||||
</PopupWrapper>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import PopupWrapper from './Components/PopupWrapper'
|
||||
import PopupActions from './Components/PopupActions'
|
||||
import ButtonBase from '../UI/Buttons/ButtonBase'
|
||||
import { events } from '../../bus'
|
||||
|
||||
export default {
|
||||
name: 'ConfirmPopup',
|
||||
components: {
|
||||
PopupWrapper,
|
||||
PopupActions,
|
||||
ButtonBase,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
confirmationData: [],
|
||||
message: undefined,
|
||||
title: undefined,
|
||||
buttonColor: undefined,
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
closePopup() {
|
||||
events.$emit('popup:close')
|
||||
},
|
||||
confirm() {
|
||||
// Close popup
|
||||
events.$emit('popup:close')
|
||||
|
||||
// Confirmation popup
|
||||
events.$emit('action:confirmed', this.confirmationData)
|
||||
|
||||
// Clear confirmation data
|
||||
this.confirmationData = []
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
// Show confirm
|
||||
events.$on('confirm:open', (args) => {
|
||||
this.title = args.title
|
||||
this.message = args.message
|
||||
this.confirmationData = args.action
|
||||
this.buttonColor = 'danger'
|
||||
|
||||
if (args.buttonColor) {
|
||||
this.buttonColor = args.buttonColor
|
||||
}
|
||||
})
|
||||
},
|
||||
}
|
||||
</script>
|
||||
113
resources/js/components/Popups/CreateFolderPopup.vue
Normal file
113
resources/js/components/Popups/CreateFolderPopup.vue
Normal file
@@ -0,0 +1,113 @@
|
||||
<template>
|
||||
<PopupWrapper name="create-folder">
|
||||
<!--Title-->
|
||||
<PopupHeader :title="$t('popup_create_folder.title')" icon="edit" />
|
||||
|
||||
<!--Content-->
|
||||
<PopupContent>
|
||||
<!--Form to set sharing-->
|
||||
<ValidationObserver @submit.prevent="createFolder" ref="createForm" v-slot="{ invalid }" tag="form">
|
||||
<!--Set folder name-->
|
||||
<ValidationProvider tag="div" mode="passive" name="Title" rules="required" v-slot="{ errors }">
|
||||
<AppInputText :title="$t('popup_create_folder.label')" :error="errors[0]">
|
||||
<input
|
||||
v-model="name"
|
||||
:class="{ '!border-rose-600': errors[0] }"
|
||||
type="text"
|
||||
ref="input"
|
||||
class="focus-border-theme input-dark"
|
||||
:placeholder="$t('popup_create_folder.placeholder')"
|
||||
/>
|
||||
</AppInputText>
|
||||
</ValidationProvider>
|
||||
|
||||
<AppInputSwitch
|
||||
:title="$t('emoji_as_an_icon')"
|
||||
:description="$t('replace_icon_with_emoji')"
|
||||
:is-last="!isEmoji"
|
||||
>
|
||||
<SwitchInput v-model="isEmoji" :state="isEmoji" />
|
||||
</AppInputSwitch>
|
||||
|
||||
<!--Set emoji-->
|
||||
<EmojiPicker v-if="isEmoji" v-model="emoji" :default-emoji="emoji" />
|
||||
</ValidationObserver>
|
||||
</PopupContent>
|
||||
|
||||
<!--Actions-->
|
||||
<PopupActions>
|
||||
<ButtonBase class="w-full" @click.native="$closePopup()" button-style="secondary"
|
||||
>{{ $t('cancel') }}
|
||||
</ButtonBase>
|
||||
<ButtonBase class="w-full" @click.native="createFolder" button-style="theme"
|
||||
>{{ $t('popup_create_folder.title') }}
|
||||
</ButtonBase>
|
||||
</PopupActions>
|
||||
</PopupWrapper>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { ValidationProvider, ValidationObserver } from 'vee-validate/dist/vee-validate.full'
|
||||
import PopupWrapper from './Components/PopupWrapper'
|
||||
import PopupActions from './Components/PopupActions'
|
||||
import PopupContent from './Components/PopupContent'
|
||||
import PopupHeader from './Components/PopupHeader'
|
||||
import ThumbnailItem from '../UI/Entries/ThumbnailItem'
|
||||
import ButtonBase from '../UI/Buttons/ButtonBase'
|
||||
import { required } from 'vee-validate/dist/rules'
|
||||
import AppInputSwitch from '../Forms/Layouts/AppInputSwitch'
|
||||
import AppInputText from '../Forms/Layouts/AppInputText'
|
||||
import SwitchInput from '../Inputs/SwitchInput'
|
||||
import { events } from '../../bus'
|
||||
import EmojiPicker from '../Emoji/EmojiPicker'
|
||||
|
||||
export default {
|
||||
name: 'CreateFolderPopup',
|
||||
components: {
|
||||
AppInputSwitch,
|
||||
SwitchInput,
|
||||
EmojiPicker,
|
||||
AppInputText,
|
||||
ValidationProvider,
|
||||
ValidationObserver,
|
||||
ThumbnailItem,
|
||||
PopupWrapper,
|
||||
PopupActions,
|
||||
PopupContent,
|
||||
PopupHeader,
|
||||
ButtonBase,
|
||||
required,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
name: undefined,
|
||||
isEmoji: false,
|
||||
emoji: undefined,
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
async createFolder() {
|
||||
// Validate fields
|
||||
const isValid = await this.$refs.createForm.validate()
|
||||
|
||||
if (!isValid) return
|
||||
|
||||
await this.$store.dispatch('createFolder', {
|
||||
name: this.name,
|
||||
emoji: this.emoji,
|
||||
})
|
||||
|
||||
this.$closePopup()
|
||||
|
||||
this.name = undefined
|
||||
this.isEmoji = false
|
||||
this.emoji = undefined
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
events.$on('popup:open', ({ name }) => {
|
||||
if (name === 'create-folder' && !this.$isMobile()) this.$nextTick(() => this.$refs.input.focus())
|
||||
})
|
||||
},
|
||||
}
|
||||
</script>
|
||||
866
resources/js/components/Popups/CreateLanguagePopup.vue
Normal file
866
resources/js/components/Popups/CreateLanguagePopup.vue
Normal file
@@ -0,0 +1,866 @@
|
||||
<template>
|
||||
<PopupWrapper name="create-language">
|
||||
<!--Title-->
|
||||
<PopupHeader :title="$t('create_language')" icon="edit" />
|
||||
|
||||
<!--Content-->
|
||||
<PopupContent class="!overflow-initial">
|
||||
<!--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 }"
|
||||
>
|
||||
<AppInputText :title="$t('select_locale')" :error="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 }">
|
||||
<AppInputText :title="$t('locale_name')" :error="errors[0]" :is-last="true">
|
||||
<input
|
||||
v-model="form.name"
|
||||
:class="{ '!border-rose-600': errors[0] }"
|
||||
type="text"
|
||||
ref="input"
|
||||
class="focus-border-theme input-dark"
|
||||
:placeholder="$t('type_language_name')"
|
||||
/>
|
||||
</AppInputText>
|
||||
</ValidationProvider>
|
||||
</ValidationObserver>
|
||||
</PopupContent>
|
||||
|
||||
<!--Actions-->
|
||||
<PopupActions>
|
||||
<ButtonBase class="w-full" @click.native="$closePopup()" button-style="secondary">
|
||||
{{ $t('cancel') }}
|
||||
</ButtonBase>
|
||||
<ButtonBase
|
||||
class="w-full"
|
||||
@click.native="createLanguage"
|
||||
button-style="theme"
|
||||
:loading="isLoading"
|
||||
:disabled="isLoading"
|
||||
>
|
||||
{{ $t('create_language') }}
|
||||
</ButtonBase>
|
||||
</PopupActions>
|
||||
</PopupWrapper>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import AppInputText from '../Forms/Layouts/AppInputText'
|
||||
import { ValidationProvider, ValidationObserver } from 'vee-validate/dist/vee-validate.full'
|
||||
import PopupWrapper from './Components/PopupWrapper'
|
||||
import PopupActions from './Components/PopupActions'
|
||||
import PopupContent from './Components/PopupContent'
|
||||
import PopupHeader from './Components/PopupHeader'
|
||||
import SelectInput from '../Inputs/SelectInput'
|
||||
import ButtonBase from '../UI/Buttons/ButtonBase'
|
||||
import { required } from 'vee-validate/dist/rules'
|
||||
import { events } from '../../bus'
|
||||
import axios from 'axios'
|
||||
|
||||
export default {
|
||||
name: 'CreateLanguagePopup',
|
||||
components: {
|
||||
ValidationProvider,
|
||||
ValidationObserver,
|
||||
AppInputText,
|
||||
PopupWrapper,
|
||||
PopupActions,
|
||||
PopupContent,
|
||||
PopupHeader,
|
||||
SelectInput,
|
||||
ButtonBase,
|
||||
required,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
form: {
|
||||
name: undefined,
|
||||
locale: undefined,
|
||||
},
|
||||
isLoading: false,
|
||||
locales: [
|
||||
{
|
||||
value: 'ab',
|
||||
label: 'Abkhaz',
|
||||
},
|
||||
{
|
||||
value: 'aa',
|
||||
label: 'Afar',
|
||||
},
|
||||
{
|
||||
value: 'af',
|
||||
label: 'Afrikaans',
|
||||
},
|
||||
{
|
||||
value: 'ak',
|
||||
label: 'Akan',
|
||||
},
|
||||
{
|
||||
value: 'sq',
|
||||
label: 'Albanian',
|
||||
},
|
||||
{
|
||||
value: 'am',
|
||||
label: 'Amharic',
|
||||
},
|
||||
{
|
||||
value: 'ar',
|
||||
label: 'Arabic',
|
||||
},
|
||||
{
|
||||
value: 'an',
|
||||
label: 'Aragonese',
|
||||
},
|
||||
{
|
||||
value: 'hy',
|
||||
label: 'Armenian',
|
||||
},
|
||||
{
|
||||
value: 'as',
|
||||
label: 'Assamese',
|
||||
},
|
||||
{
|
||||
value: 'av',
|
||||
label: 'Avaric',
|
||||
},
|
||||
{
|
||||
value: 'ae',
|
||||
label: 'Avestan',
|
||||
},
|
||||
{
|
||||
value: 'ay',
|
||||
label: 'Aymara',
|
||||
},
|
||||
{
|
||||
value: 'az',
|
||||
label: 'Azerbaijani',
|
||||
},
|
||||
{
|
||||
value: 'bm',
|
||||
label: 'Bambara',
|
||||
},
|
||||
{
|
||||
value: 'ba',
|
||||
label: 'Bashkir',
|
||||
},
|
||||
{
|
||||
value: 'eu',
|
||||
label: 'Basque',
|
||||
},
|
||||
{
|
||||
value: 'be',
|
||||
label: 'Belarusian',
|
||||
},
|
||||
{
|
||||
value: 'bn',
|
||||
label: 'Bengali; Bangla',
|
||||
},
|
||||
{
|
||||
value: 'bh',
|
||||
label: 'Bihari',
|
||||
},
|
||||
{
|
||||
value: 'bi',
|
||||
label: 'Bislama',
|
||||
},
|
||||
{
|
||||
value: 'bs',
|
||||
label: 'Bosnian',
|
||||
},
|
||||
{
|
||||
value: 'br',
|
||||
label: 'Breton',
|
||||
},
|
||||
{
|
||||
value: 'bg',
|
||||
label: 'Bulgarian',
|
||||
},
|
||||
{
|
||||
value: 'my',
|
||||
label: 'Burmese',
|
||||
},
|
||||
{
|
||||
value: 'ca',
|
||||
label: 'Catalan; Valencian',
|
||||
},
|
||||
{
|
||||
value: 'ch',
|
||||
label: 'Chamorro',
|
||||
},
|
||||
{
|
||||
value: 'ce',
|
||||
label: 'Chechen',
|
||||
},
|
||||
{
|
||||
value: 'ny',
|
||||
label: 'Chichewa; Chewa; Nyanja',
|
||||
},
|
||||
{
|
||||
value: 'zh',
|
||||
label: 'Chinese',
|
||||
},
|
||||
{
|
||||
value: 'cv',
|
||||
label: 'Chuvash',
|
||||
},
|
||||
{
|
||||
value: 'kw',
|
||||
label: 'Cornish',
|
||||
},
|
||||
{
|
||||
value: 'co',
|
||||
label: 'Corsican',
|
||||
},
|
||||
{
|
||||
value: 'cr',
|
||||
label: 'Cree',
|
||||
},
|
||||
{
|
||||
value: 'hr',
|
||||
label: 'Croatian',
|
||||
},
|
||||
{
|
||||
value: 'cs',
|
||||
label: 'Czech',
|
||||
},
|
||||
{
|
||||
value: 'da',
|
||||
label: 'Danish',
|
||||
},
|
||||
{
|
||||
value: 'dv',
|
||||
label: 'Divehi; Dhivehi; Maldivian;',
|
||||
},
|
||||
{
|
||||
value: 'nl',
|
||||
label: 'Dutch',
|
||||
},
|
||||
{
|
||||
value: 'dz',
|
||||
label: 'Dzongkha',
|
||||
},
|
||||
{
|
||||
value: 'en',
|
||||
label: 'English',
|
||||
},
|
||||
{
|
||||
value: 'eo',
|
||||
label: 'Esperanto',
|
||||
},
|
||||
{
|
||||
value: 'et',
|
||||
label: 'Estonian',
|
||||
},
|
||||
{
|
||||
value: 'ee',
|
||||
label: 'Ewe',
|
||||
},
|
||||
{
|
||||
value: 'fo',
|
||||
label: 'Faroese',
|
||||
},
|
||||
{
|
||||
value: 'fj',
|
||||
label: 'Fijian',
|
||||
},
|
||||
{
|
||||
value: 'fi',
|
||||
label: 'Finnish',
|
||||
},
|
||||
{
|
||||
value: 'fr',
|
||||
label: 'French',
|
||||
},
|
||||
{
|
||||
value: 'ff',
|
||||
label: 'Fula; Fulah; Pulaar; Pular',
|
||||
},
|
||||
{
|
||||
value: 'gl',
|
||||
label: 'Galician',
|
||||
},
|
||||
{
|
||||
value: 'lg',
|
||||
label: 'Ganda',
|
||||
},
|
||||
{
|
||||
value: 'ka',
|
||||
label: 'Georgian',
|
||||
},
|
||||
{
|
||||
value: 'de',
|
||||
label: 'German',
|
||||
},
|
||||
{
|
||||
value: 'el',
|
||||
label: 'Greek, Modern',
|
||||
},
|
||||
{
|
||||
value: 'gn',
|
||||
label: 'GuaranÃ',
|
||||
},
|
||||
{
|
||||
value: 'gu',
|
||||
label: 'Gujarati',
|
||||
},
|
||||
{
|
||||
value: 'ht',
|
||||
label: 'Haitian; Haitian Creole',
|
||||
},
|
||||
{
|
||||
value: 'ha',
|
||||
label: 'Hausa',
|
||||
},
|
||||
{
|
||||
value: 'he',
|
||||
label: 'Hebrew (modern)',
|
||||
},
|
||||
{
|
||||
value: 'hz',
|
||||
label: 'Herero',
|
||||
},
|
||||
{
|
||||
value: 'hi',
|
||||
label: 'Hindi',
|
||||
},
|
||||
{
|
||||
value: 'ho',
|
||||
label: 'Hiri Motu',
|
||||
},
|
||||
{
|
||||
value: 'hu',
|
||||
label: 'Hungarian',
|
||||
},
|
||||
{
|
||||
value: 'ia',
|
||||
label: 'Interlingua',
|
||||
},
|
||||
{
|
||||
value: 'id',
|
||||
label: 'Indonesian',
|
||||
},
|
||||
{
|
||||
value: 'ie',
|
||||
label: 'Interlingue',
|
||||
},
|
||||
{
|
||||
value: 'ga',
|
||||
label: 'Irish',
|
||||
},
|
||||
{
|
||||
value: 'ig',
|
||||
label: 'Igbo',
|
||||
},
|
||||
{
|
||||
value: 'ik',
|
||||
label: 'Inupiaq',
|
||||
},
|
||||
{
|
||||
value: 'io',
|
||||
label: 'Ido',
|
||||
},
|
||||
{
|
||||
value: 'is',
|
||||
label: 'Icelandic',
|
||||
},
|
||||
{
|
||||
value: 'it',
|
||||
label: 'Italian',
|
||||
},
|
||||
{
|
||||
value: 'iu',
|
||||
label: 'Inuktitut',
|
||||
},
|
||||
{
|
||||
value: 'ja',
|
||||
label: 'Japanese',
|
||||
},
|
||||
{
|
||||
value: 'jv',
|
||||
label: 'Javanese',
|
||||
},
|
||||
{
|
||||
value: 'kl',
|
||||
label: 'Kalaallisut, Greenlandic',
|
||||
},
|
||||
{
|
||||
value: 'kn',
|
||||
label: 'Kannada',
|
||||
},
|
||||
{
|
||||
value: 'kr',
|
||||
label: 'Kanuri',
|
||||
},
|
||||
{
|
||||
value: 'ks',
|
||||
label: 'Kashmiri',
|
||||
},
|
||||
{
|
||||
value: 'kk',
|
||||
label: 'Kazakh',
|
||||
},
|
||||
{
|
||||
value: 'km',
|
||||
label: 'Khmer',
|
||||
},
|
||||
{
|
||||
value: 'ki',
|
||||
label: 'Kikuyu, Gikuyu',
|
||||
},
|
||||
{
|
||||
value: 'rw',
|
||||
label: 'Kinyarwanda',
|
||||
},
|
||||
{
|
||||
value: 'rn',
|
||||
label: 'Kirundi',
|
||||
},
|
||||
{
|
||||
value: 'ky',
|
||||
label: 'Kyrgyz',
|
||||
},
|
||||
{
|
||||
value: 'kv',
|
||||
label: 'Komi',
|
||||
},
|
||||
{
|
||||
value: 'kg',
|
||||
label: 'Kongo',
|
||||
},
|
||||
{
|
||||
value: 'ko',
|
||||
label: 'Korean',
|
||||
},
|
||||
{
|
||||
value: 'ku',
|
||||
label: 'Kurdish',
|
||||
},
|
||||
{
|
||||
value: 'kj',
|
||||
label: 'Kwanyama, Kuanyama',
|
||||
},
|
||||
{
|
||||
value: 'la',
|
||||
label: 'Latin',
|
||||
},
|
||||
{
|
||||
value: 'lb',
|
||||
label: 'Luxembourgish, Letzeburgesch',
|
||||
},
|
||||
{
|
||||
value: 'li',
|
||||
label: 'Limburgish, Limburgan, Limburger',
|
||||
},
|
||||
{
|
||||
value: 'ln',
|
||||
label: 'Lingala',
|
||||
},
|
||||
{
|
||||
value: 'lo',
|
||||
label: 'Lao',
|
||||
},
|
||||
{
|
||||
value: 'lt',
|
||||
label: 'Lithuanian',
|
||||
},
|
||||
{
|
||||
value: 'lu',
|
||||
label: 'Luba-Katanga',
|
||||
},
|
||||
{
|
||||
value: 'lv',
|
||||
label: 'Latvian',
|
||||
},
|
||||
{
|
||||
value: 'gv',
|
||||
label: 'Manx',
|
||||
},
|
||||
{
|
||||
value: 'mk',
|
||||
label: 'Macedonian',
|
||||
},
|
||||
{
|
||||
value: 'mg',
|
||||
label: 'Malagasy',
|
||||
},
|
||||
{
|
||||
value: 'ms',
|
||||
label: 'Malay',
|
||||
},
|
||||
{
|
||||
value: 'ml',
|
||||
label: 'Malayalam',
|
||||
},
|
||||
{
|
||||
value: 'mt',
|
||||
label: 'Maltese',
|
||||
},
|
||||
{
|
||||
value: 'mi',
|
||||
label: 'MÄori',
|
||||
},
|
||||
{
|
||||
value: 'mr',
|
||||
label: 'Marathi',
|
||||
},
|
||||
{
|
||||
value: 'mh',
|
||||
label: 'Marshallese',
|
||||
},
|
||||
{
|
||||
value: 'mn',
|
||||
label: 'Mongolian',
|
||||
},
|
||||
{
|
||||
value: 'na',
|
||||
label: 'Nauru',
|
||||
},
|
||||
{
|
||||
value: 'nv',
|
||||
label: 'Navajo, Navaho',
|
||||
},
|
||||
{
|
||||
value: 'nb',
|
||||
label: 'Norwegian',
|
||||
},
|
||||
{
|
||||
value: 'nd',
|
||||
label: 'North Ndebele',
|
||||
},
|
||||
{
|
||||
value: 'ne',
|
||||
label: 'Nepali',
|
||||
},
|
||||
{
|
||||
value: 'ng',
|
||||
label: 'Ndonga',
|
||||
},
|
||||
{
|
||||
value: 'nn',
|
||||
label: 'Norwegian Nynorsk',
|
||||
},
|
||||
{
|
||||
value: 'no',
|
||||
label: 'Norwegian',
|
||||
},
|
||||
{
|
||||
value: 'ii',
|
||||
label: 'Nuosu',
|
||||
},
|
||||
{
|
||||
value: 'oc',
|
||||
label: 'Occitan',
|
||||
},
|
||||
{
|
||||
value: 'oj',
|
||||
label: 'Ojibwe, Ojibwa',
|
||||
},
|
||||
{
|
||||
value: 'cu',
|
||||
label: 'Old Church Slavonic, Church Slavic, Church Slavonic, Old Bulgarian, Old Slavonic',
|
||||
},
|
||||
{
|
||||
value: 'om',
|
||||
label: 'Oromo',
|
||||
},
|
||||
{
|
||||
value: 'or',
|
||||
label: 'Oriya',
|
||||
},
|
||||
{
|
||||
value: 'os',
|
||||
label: 'Ossetian, Ossetic',
|
||||
},
|
||||
{
|
||||
value: 'pa',
|
||||
label: 'Panjabi, Punjabi',
|
||||
},
|
||||
{
|
||||
value: 'pi',
|
||||
label: 'Pali',
|
||||
},
|
||||
{
|
||||
value: 'fa',
|
||||
label: 'Persian (Farsi)',
|
||||
},
|
||||
{
|
||||
value: 'pl',
|
||||
label: 'Polish',
|
||||
},
|
||||
{
|
||||
value: 'ps',
|
||||
label: 'Pashto, Pushto',
|
||||
},
|
||||
{
|
||||
value: 'pt',
|
||||
label: 'Portuguese',
|
||||
},
|
||||
{
|
||||
value: 'qu',
|
||||
label: 'Quechua',
|
||||
},
|
||||
{
|
||||
value: 'rm',
|
||||
label: 'Romansh',
|
||||
},
|
||||
{
|
||||
value: 'ro',
|
||||
label: 'Romanian',
|
||||
},
|
||||
{
|
||||
value: 'ru',
|
||||
label: 'Russian',
|
||||
},
|
||||
{
|
||||
value: 'sa',
|
||||
label: 'Sanskrit',
|
||||
},
|
||||
{
|
||||
value: 'sc',
|
||||
label: 'Sardinian',
|
||||
},
|
||||
{
|
||||
value: 'sd',
|
||||
label: 'Sindhi',
|
||||
},
|
||||
{
|
||||
value: 'se',
|
||||
label: 'Northern Sami',
|
||||
},
|
||||
{
|
||||
value: 'sm',
|
||||
label: 'Samoan',
|
||||
},
|
||||
{
|
||||
value: 'sg',
|
||||
label: 'Sango',
|
||||
},
|
||||
{
|
||||
value: 'sr',
|
||||
label: 'Serbian',
|
||||
},
|
||||
{
|
||||
value: 'gd',
|
||||
label: 'Scottish Gaelic',
|
||||
},
|
||||
{
|
||||
value: 'sn',
|
||||
label: 'Shona',
|
||||
},
|
||||
{
|
||||
value: 'si',
|
||||
label: 'Sinhala, Sinhalese',
|
||||
},
|
||||
{
|
||||
value: 'sk',
|
||||
label: 'Slovak',
|
||||
},
|
||||
{
|
||||
value: 'sl',
|
||||
label: 'Slovene',
|
||||
},
|
||||
{
|
||||
value: 'so',
|
||||
label: 'Somali',
|
||||
},
|
||||
{
|
||||
value: 'st',
|
||||
label: 'Southern Sotho',
|
||||
},
|
||||
{
|
||||
value: 'az',
|
||||
label: 'South Azerbaijani',
|
||||
},
|
||||
{
|
||||
value: 'nr',
|
||||
label: 'South Ndebele',
|
||||
},
|
||||
{
|
||||
value: 'es',
|
||||
label: 'Spanish; Castilian',
|
||||
},
|
||||
{
|
||||
value: 'su',
|
||||
label: 'Sundanese',
|
||||
},
|
||||
{
|
||||
value: 'sw',
|
||||
label: 'Swahili',
|
||||
},
|
||||
{
|
||||
value: 'ss',
|
||||
label: 'Swati',
|
||||
},
|
||||
{
|
||||
value: 'sv',
|
||||
label: 'Swedish',
|
||||
},
|
||||
{
|
||||
value: 'ta',
|
||||
label: 'Tamil',
|
||||
},
|
||||
{
|
||||
value: 'te',
|
||||
label: 'Telugu',
|
||||
},
|
||||
{
|
||||
value: 'tg',
|
||||
label: 'Tajik',
|
||||
},
|
||||
{
|
||||
value: 'th',
|
||||
label: 'Thai',
|
||||
},
|
||||
{
|
||||
value: 'ti',
|
||||
label: 'Tigrinya',
|
||||
},
|
||||
{
|
||||
value: 'bo',
|
||||
label: 'Tibetan Standard, Tibetan, Central',
|
||||
},
|
||||
{
|
||||
value: 'tk',
|
||||
label: 'Turkmen',
|
||||
},
|
||||
{
|
||||
value: 'tl',
|
||||
label: 'Tagalog',
|
||||
},
|
||||
{
|
||||
value: 'tn',
|
||||
label: 'Tswana',
|
||||
},
|
||||
{
|
||||
value: 'to',
|
||||
label: 'Tonga (Tonga Islands)',
|
||||
},
|
||||
{
|
||||
value: 'tr',
|
||||
label: 'Turkish',
|
||||
},
|
||||
{
|
||||
value: 'ts',
|
||||
label: 'Tsonga',
|
||||
},
|
||||
{
|
||||
value: 'tt',
|
||||
label: 'Tatar',
|
||||
},
|
||||
{
|
||||
value: 'tw',
|
||||
label: 'Twi',
|
||||
},
|
||||
{
|
||||
value: 'ty',
|
||||
label: 'Tahitian',
|
||||
},
|
||||
{
|
||||
value: 'ug',
|
||||
label: 'Uyghur, Uighur',
|
||||
},
|
||||
{
|
||||
value: 'uk',
|
||||
label: 'Ukrainian',
|
||||
},
|
||||
{
|
||||
value: 'ur',
|
||||
label: 'Urdu',
|
||||
},
|
||||
{
|
||||
value: 'uz',
|
||||
label: 'Uzbek',
|
||||
},
|
||||
{
|
||||
value: 've',
|
||||
label: 'Venda',
|
||||
},
|
||||
{
|
||||
value: 'vi',
|
||||
label: 'Vielabele',
|
||||
},
|
||||
{
|
||||
value: 'vo',
|
||||
label: 'Volapük',
|
||||
},
|
||||
{
|
||||
value: 'wa',
|
||||
label: 'Walloon',
|
||||
},
|
||||
{
|
||||
value: 'cy',
|
||||
label: 'Welsh',
|
||||
},
|
||||
{
|
||||
value: 'wo',
|
||||
label: 'Wolof',
|
||||
},
|
||||
{
|
||||
value: 'fy',
|
||||
label: 'Western Frisian',
|
||||
},
|
||||
{
|
||||
value: 'xh',
|
||||
label: 'Xhosa',
|
||||
},
|
||||
{
|
||||
value: 'yi',
|
||||
label: 'Yiddish',
|
||||
},
|
||||
{
|
||||
value: 'yo',
|
||||
label: 'Yoruba',
|
||||
},
|
||||
{
|
||||
value: 'za',
|
||||
label: 'Zhuang, Chuang',
|
||||
},
|
||||
{
|
||||
value: 'zu',
|
||||
label: 'Zulu',
|
||||
},
|
||||
],
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
async createLanguage() {
|
||||
// Validate fields
|
||||
const isValid = await this.$refs.createForm.validate()
|
||||
|
||||
if (isValid) {
|
||||
this.isLoading = true
|
||||
|
||||
axios
|
||||
.post('/api/admin/languages', this.form)
|
||||
.then((response) => {
|
||||
events.$emit('reload:languages', response.data)
|
||||
})
|
||||
.catch(() => {
|
||||
this.$isSomethingWrong()
|
||||
})
|
||||
.finally(() => {
|
||||
this.form = {
|
||||
name: undefined,
|
||||
locale: undefined,
|
||||
}
|
||||
|
||||
this.isLoading = false
|
||||
this.$closePopup()
|
||||
})
|
||||
}
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
134
resources/js/components/Popups/CreatePersonalTokenPopup.vue
Normal file
134
resources/js/components/Popups/CreatePersonalTokenPopup.vue
Normal file
@@ -0,0 +1,134 @@
|
||||
<template>
|
||||
<PopupWrapper name="create-personal-token">
|
||||
<PopupHeader :title="$t('create_personal_token')" icon="key" />
|
||||
|
||||
<PopupContent>
|
||||
<ValidationObserver
|
||||
v-if="!token"
|
||||
@submit.prevent="createTokenForm"
|
||||
ref="createToken"
|
||||
v-slot="{ invalid }"
|
||||
tag="form"
|
||||
>
|
||||
<ValidationProvider tag="div" mode="passive" name="Token Name" rules="required|min:3" v-slot="{ errors }">
|
||||
<AppInputText :title="$t('token_name')" :error="errors[0]" :is-last="true">
|
||||
<input
|
||||
v-model="name"
|
||||
:class="{ '!border-rose-600': errors[0] }"
|
||||
type="text"
|
||||
ref="input"
|
||||
class="focus-border-theme input-dark"
|
||||
:placeholder="$t('popup_personal_token.plc')"
|
||||
/>
|
||||
</AppInputText>
|
||||
</ValidationProvider>
|
||||
</ValidationObserver>
|
||||
|
||||
<AppInputText v-if="token" :title="$t('popup_personal_token.your_token')" :is-last="true">
|
||||
<CopyInput size="small" :str="token['plainTextToken']" />
|
||||
|
||||
<InfoBox style="margin-bottom: 0; margin-top: 20px">
|
||||
<p v-html="$t('popup_personal_token.copy_token')"></p>
|
||||
</InfoBox>
|
||||
</AppInputText>
|
||||
</PopupContent>
|
||||
|
||||
<PopupActions v-if="!token">
|
||||
<ButtonBase class="w-full" @click.native="$closePopup()" button-style="secondary">
|
||||
{{ $t('cancel') }}
|
||||
</ButtonBase>
|
||||
<ButtonBase
|
||||
class="w-full"
|
||||
@click.native="createTokenForm"
|
||||
button-style="theme"
|
||||
:loading="isLoading"
|
||||
:disabled="isLoading"
|
||||
>
|
||||
{{ $t('create_token') }}
|
||||
</ButtonBase>
|
||||
</PopupActions>
|
||||
|
||||
<PopupActions v-if="token">
|
||||
<ButtonBase class="w-full" @click.native="$closePopup" button-style="theme">
|
||||
{{ $t('awesome_iam_done') }}
|
||||
</ButtonBase>
|
||||
</PopupActions>
|
||||
</PopupWrapper>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import AppInputText from '../Forms/Layouts/AppInputText'
|
||||
import { ValidationProvider, ValidationObserver } from 'vee-validate/dist/vee-validate.full'
|
||||
import PopupWrapper from './Components/PopupWrapper'
|
||||
import PopupActions from './Components/PopupActions'
|
||||
import PopupContent from './Components/PopupContent'
|
||||
import PopupHeader from './Components/PopupHeader'
|
||||
import CopyInput from '../Inputs/CopyInput'
|
||||
import ButtonBase from '../UI/Buttons/ButtonBase'
|
||||
import InfoBox from '../UI/Others/InfoBox'
|
||||
import { required } from 'vee-validate/dist/rules'
|
||||
import { events } from '../../bus'
|
||||
import axios from 'axios'
|
||||
|
||||
export default {
|
||||
name: 'CreatePersonalTokenPopup',
|
||||
components: {
|
||||
ValidationProvider,
|
||||
ValidationObserver,
|
||||
AppInputText,
|
||||
PopupWrapper,
|
||||
PopupActions,
|
||||
PopupContent,
|
||||
PopupHeader,
|
||||
ButtonBase,
|
||||
CopyInput,
|
||||
required,
|
||||
InfoBox,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
isLoading: false,
|
||||
name: undefined,
|
||||
token: undefined,
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
async createTokenForm() {
|
||||
const isValid = await this.$refs.createToken.validate()
|
||||
|
||||
if (!isValid) return
|
||||
|
||||
this.isLoading = true
|
||||
|
||||
axios
|
||||
.post('/api/user/tokens', {
|
||||
name: this.name,
|
||||
})
|
||||
.then((response) => {
|
||||
this.token = response.data
|
||||
|
||||
events.$emit('reload-personal-access-tokens')
|
||||
})
|
||||
.catch(() => this.$isSomethingWrong())
|
||||
.finally(() => {
|
||||
this.isLoading = false
|
||||
this.name = undefined
|
||||
})
|
||||
},
|
||||
},
|
||||
created() {
|
||||
events.$on('popup:close', () => this.token = undefined)
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@import '../../../sass/vuefilemanager/inapp-forms';
|
||||
@import '../../../sass/vuefilemanager/forms';
|
||||
|
||||
.dark {
|
||||
.info-box {
|
||||
background: lighten($dark_mode_foreground, 3%);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
160
resources/js/components/Popups/MoveItemPopup.vue
Normal file
160
resources/js/components/Popups/MoveItemPopup.vue
Normal file
@@ -0,0 +1,160 @@
|
||||
<template>
|
||||
<PopupWrapper name="move">
|
||||
<!--Title-->
|
||||
<PopupHeader :title="$t('popup_move_item.title')" icon="move" />
|
||||
|
||||
<!--Content-->
|
||||
<PopupContent v-if="pickedItem" class="h-full pb-6 lg:max-h-96 sm:overflow-y-auto md:pb-0">
|
||||
<!--Show Spinner when loading folders-->
|
||||
<Spinner v-if="isLoadingTree" />
|
||||
|
||||
<!--Folder tree-->
|
||||
<div v-if="!isLoadingTree && navigation">
|
||||
<ThumbnailItem v-if="clipboard.length === 1 || isSelectedItem" class="mb-5" :item="pickedItem" />
|
||||
|
||||
<TitlePreview
|
||||
class="mb-4"
|
||||
icon="check-square"
|
||||
:title="$t('selected_multiple')"
|
||||
:subtitle="clipboard.length + ' ' + $tc('items', clipboard.length)"
|
||||
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"
|
||||
/>
|
||||
</div>
|
||||
</PopupContent>
|
||||
|
||||
<!--Actions-->
|
||||
<PopupActions>
|
||||
<ButtonBase class="w-full" @click.native="$closePopup()" button-style="secondary"
|
||||
>{{ $t('cancel') }}
|
||||
</ButtonBase>
|
||||
<ButtonBase class="w-full" @click.native="moveItem" :button-style="selectedFolder ? 'theme' : 'secondary'"
|
||||
>{{ $t('popup_move_item.submit') }}
|
||||
</ButtonBase>
|
||||
</PopupActions>
|
||||
</PopupWrapper>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import PopupWrapper from './Components/PopupWrapper'
|
||||
import PopupActions from './Components/PopupActions'
|
||||
import TitlePreview from '../UI/Labels/TitlePreview'
|
||||
import PopupContent from './Components/PopupContent'
|
||||
import PopupHeader from './Components/PopupHeader'
|
||||
import ThumbnailItem from '../UI/Entries/ThumbnailItem'
|
||||
import ButtonBase from '../UI/Buttons/ButtonBase'
|
||||
import Spinner from '../UI/Others/Spinner'
|
||||
import TreeMenu from '../UI/Trees/TreeMenu'
|
||||
import { isArray } from 'lodash'
|
||||
import { mapGetters } from 'vuex'
|
||||
import { events } from '../../bus'
|
||||
|
||||
export default {
|
||||
name: 'MoveItemPopup',
|
||||
components: {
|
||||
ThumbnailItem,
|
||||
TitlePreview,
|
||||
PopupWrapper,
|
||||
PopupActions,
|
||||
PopupContent,
|
||||
PopupHeader,
|
||||
ButtonBase,
|
||||
TreeMenu,
|
||||
Spinner,
|
||||
},
|
||||
computed: {
|
||||
...mapGetters(['navigation', 'clipboard']),
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
selectedFolder: undefined,
|
||||
pickedItem: undefined,
|
||||
isLoadingTree: true,
|
||||
isSelectedItem: false,
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
moveItem() {
|
||||
// Prevent empty submit
|
||||
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
|
||||
|
||||
// Move item
|
||||
this.$store.dispatch('moveItem', {
|
||||
to_item: this.selectedFolder,
|
||||
item: this.isSelectedItem ? this.pickedItem : undefined,
|
||||
})
|
||||
|
||||
// Close popup
|
||||
events.$emit('popup:close')
|
||||
|
||||
// If is mobile, close the selecting mod after done the move action
|
||||
if (this.$isMobile())
|
||||
this.$store.commit('DISABLE_MULTISELECT_MODE')
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
events.$on('pick-folder', (folder) => {
|
||||
if (folder.id === this.pickedItem.data.id) {
|
||||
this.selectedFolder = undefined
|
||||
} else if (!folder.id && folder.location === 'base') {
|
||||
this.selectedFolder = 'base'
|
||||
} else {
|
||||
this.selectedFolder = folder
|
||||
}
|
||||
})
|
||||
|
||||
// Show Move item popup
|
||||
events.$on('popup:open', (args) => {
|
||||
if (args.name !== 'move') return
|
||||
|
||||
// Show tree spinner
|
||||
this.isLoadingTree = true
|
||||
|
||||
// Get folder tree and hide spinner
|
||||
if (this.$isThisRoute(this.$route, ['SharedWithMe'])) {
|
||||
this.$store.dispatch('getTeamFolderTree').then(() => {
|
||||
this.isLoadingTree = false
|
||||
})
|
||||
} else {
|
||||
this.$store.dispatch('getFolderTree').then(() => {
|
||||
this.isLoadingTree = false
|
||||
})
|
||||
}
|
||||
|
||||
// Store picked item
|
||||
if (!this.clipboard.includes(args.item[0])) {
|
||||
this.pickedItem = args.item[0]
|
||||
this.isSelectedItem = true
|
||||
}
|
||||
|
||||
if (this.clipboard.includes(args.item[0])) {
|
||||
this.pickedItem = this.clipboard[0]
|
||||
this.isSelectedItem = false
|
||||
}
|
||||
})
|
||||
|
||||
// Close popup
|
||||
events.$on('popup:close', () => {
|
||||
// Clear selected folder
|
||||
setTimeout(() => {
|
||||
this.selectedFolder = undefined
|
||||
}, 150)
|
||||
})
|
||||
},
|
||||
}
|
||||
</script>
|
||||
134
resources/js/components/Popups/ProcessingPopup.vue
Normal file
134
resources/js/components/Popups/ProcessingPopup.vue
Normal file
@@ -0,0 +1,134 @@
|
||||
<template>
|
||||
<transition name="popup">
|
||||
<div class="popup" v-if="processingPopup">
|
||||
<div class="popup-wrapper">
|
||||
<div class="popup-content">
|
||||
<div class="spinner-wrapper">
|
||||
<Spinner />
|
||||
</div>
|
||||
<h1 class="title">{{ processingPopup.title }}</h1>
|
||||
<p class="message">{{ processingPopup.message }}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</transition>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import Spinner from '../UI/Others/Spinner'
|
||||
import { mapGetters } from 'vuex'
|
||||
|
||||
export default {
|
||||
name: 'ProcessingPopup',
|
||||
components: {
|
||||
Spinner,
|
||||
},
|
||||
computed: {
|
||||
...mapGetters(['processingPopup']),
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
@import '../../../sass/vuefilemanager/variables';
|
||||
@import '../../../sass/vuefilemanager/mixins';
|
||||
|
||||
.spinner-wrapper {
|
||||
padding-bottom: 90px;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.popup {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
z-index: 20;
|
||||
overflow: auto;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.popup-wrapper {
|
||||
z-index: 12;
|
||||
position: absolute;
|
||||
left: 0;
|
||||
right: 0;
|
||||
max-width: 480px;
|
||||
top: 50%;
|
||||
transform: translateY(-50%) scale(1);
|
||||
margin: 0 auto;
|
||||
padding: 20px;
|
||||
box-shadow: $light_mode_popup_shadow;
|
||||
border-radius: 8px;
|
||||
text-align: center;
|
||||
background: white;
|
||||
}
|
||||
|
||||
.popup-content {
|
||||
.title {
|
||||
@include font-size(22);
|
||||
font-weight: 700;
|
||||
color: $text;
|
||||
}
|
||||
|
||||
.message {
|
||||
@include font-size(16);
|
||||
color: #333;
|
||||
margin-top: 5px;
|
||||
}
|
||||
}
|
||||
|
||||
@media only screen and (max-width: 690px) {
|
||||
.popup-wrapper {
|
||||
padding: 20px;
|
||||
left: 15px;
|
||||
right: 15px;
|
||||
}
|
||||
|
||||
.popup-content {
|
||||
.title {
|
||||
@include font-size(19);
|
||||
}
|
||||
|
||||
.message {
|
||||
@include font-size(15);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.dark {
|
||||
.popup-wrapper {
|
||||
background: $dark_mode_foreground;
|
||||
}
|
||||
.popup-content {
|
||||
.title {
|
||||
color: $dark_mode_text_primary;
|
||||
}
|
||||
|
||||
.message {
|
||||
color: $dark_mode_text_secondary;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Animations
|
||||
.popup-enter-active {
|
||||
animation: popup-in 0.35s 0.15s ease both;
|
||||
}
|
||||
|
||||
.popup-leave-active {
|
||||
animation: popup-in 0.15s ease reverse;
|
||||
}
|
||||
|
||||
@keyframes popup-in {
|
||||
0% {
|
||||
opacity: 0;
|
||||
transform: scale(0.7);
|
||||
}
|
||||
100% {
|
||||
opacity: 1;
|
||||
transform: scale(1);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
175
resources/js/components/Popups/RenameItemPopup.vue
Normal file
175
resources/js/components/Popups/RenameItemPopup.vue
Normal file
@@ -0,0 +1,175 @@
|
||||
<template>
|
||||
<PopupWrapper name="rename-item">
|
||||
<!--Title-->
|
||||
<PopupHeader :title="$t('popup_rename.title', { item: itemTypeTitle })" icon="edit" />
|
||||
|
||||
<!--Content-->
|
||||
<PopupContent>
|
||||
<!--Item Thumbnail-->
|
||||
<ThumbnailItem class="mb-5" :item="pickedItem" :setFolderIcon="{ emoji: emoji, color: null }" />
|
||||
|
||||
<!--Form to set sharing-->
|
||||
<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'"
|
||||
>
|
||||
<div class="relative flex items-center">
|
||||
<input
|
||||
v-model="pickedItem.data.attributes.name"
|
||||
:class="{ '!border-rose-600': errors[0] }"
|
||||
ref="input"
|
||||
type="text"
|
||||
class="!pr-10 focus-border-theme input-dark"
|
||||
:placeholder="$t('popup_rename.placeholder')"
|
||||
/>
|
||||
<div @click="pickedItem.data.attributes.name = ''" class="absolute right-0 p-4 cursor-pointer">
|
||||
<x-icon class="hover-text-theme" size="14" />
|
||||
</div>
|
||||
</div>
|
||||
</AppInputText>
|
||||
</ValidationProvider>
|
||||
|
||||
<!--Emoji-->
|
||||
<AppInputSwitch
|
||||
v-if="pickedItem.data.type === 'folder'"
|
||||
:title="$t('emoji_as_an_icon')"
|
||||
:description="$t('replace_icon_with_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"
|
||||
/>
|
||||
</ValidationObserver>
|
||||
</PopupContent>
|
||||
|
||||
<!--Actions-->
|
||||
<PopupActions>
|
||||
<ButtonBase class="w-full" @click.native="$closePopup()" button-style="secondary">
|
||||
{{ $t('cancel') }}
|
||||
</ButtonBase>
|
||||
<ButtonBase class="w-full" @click.native="changeName" button-style="theme">
|
||||
{{ $t('popup_share_edit.save') }}
|
||||
</ButtonBase>
|
||||
</PopupActions>
|
||||
</PopupWrapper>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { ValidationProvider, ValidationObserver } from 'vee-validate/dist/vee-validate.full'
|
||||
import PopupWrapper from './Components/PopupWrapper'
|
||||
import PopupActions from './Components/PopupActions'
|
||||
import PopupContent from './Components/PopupContent'
|
||||
import PopupHeader from './Components/PopupHeader'
|
||||
import ThumbnailItem from '../UI/Entries/ThumbnailItem'
|
||||
import ButtonBase from '../UI/Buttons/ButtonBase'
|
||||
import AppInputSwitch from '../Forms/Layouts/AppInputSwitch'
|
||||
import AppInputText from '../Forms/Layouts/AppInputText'
|
||||
import { required } from 'vee-validate/dist/rules'
|
||||
import SwitchInput from '../Inputs/SwitchInput'
|
||||
import EmojiPicker from '../Emoji/EmojiPicker'
|
||||
import { XIcon } from 'vue-feather-icons'
|
||||
import { events } from '../../bus'
|
||||
|
||||
export default {
|
||||
name: 'RenameItemPopup',
|
||||
components: {
|
||||
ValidationProvider,
|
||||
ValidationObserver,
|
||||
EmojiPicker,
|
||||
AppInputSwitch,
|
||||
SwitchInput,
|
||||
AppInputText,
|
||||
ThumbnailItem,
|
||||
PopupWrapper,
|
||||
PopupActions,
|
||||
PopupContent,
|
||||
PopupHeader,
|
||||
ButtonBase,
|
||||
required,
|
||||
XIcon,
|
||||
},
|
||||
computed: {
|
||||
itemTypeTitle() {
|
||||
return this.pickedItem && this.pickedItem.data.type === 'folder'
|
||||
? this.$t('folder')
|
||||
: this.$t('file')
|
||||
},
|
||||
},
|
||||
watch: {
|
||||
isEmoji(val) {
|
||||
if (!val) {
|
||||
events.$emit('setFolderIcon', { emoji: undefined })
|
||||
this.emoji = undefined
|
||||
} else {
|
||||
events.$emit('setFolderIcon', { emoji: this.emoji })
|
||||
}
|
||||
},
|
||||
emoji(val) {
|
||||
events.$emit('setFolderIcon', {
|
||||
emoji: val,
|
||||
})
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
pickedItem: undefined,
|
||||
isEmoji: false,
|
||||
emoji: undefined,
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
changeName() {
|
||||
if (this.pickedItem.data.attributes.name && this.pickedItem.data.attributes.name !== '') {
|
||||
let item = {
|
||||
id: this.pickedItem.data.id,
|
||||
type: this.pickedItem.data.type,
|
||||
name: this.pickedItem.data.attributes.name,
|
||||
}
|
||||
|
||||
item['emoji'] = this.emoji || null
|
||||
|
||||
if (!this.isEmoji) item['emoji'] = null
|
||||
|
||||
// Rename item request
|
||||
this.$store.dispatch('renameItem', item)
|
||||
|
||||
// Rename item in view
|
||||
events.$emit('change:name', item)
|
||||
|
||||
this.$closePopup()
|
||||
}
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
// Show popup
|
||||
events.$on('popup:open', (args) => {
|
||||
if (args.name !== 'rename-item') return
|
||||
|
||||
this.isEmoji = false
|
||||
|
||||
if (!this.$isMobile()) {
|
||||
this.$nextTick(() => this.$refs.input.focus())
|
||||
}
|
||||
|
||||
// Set default emoji if exist
|
||||
if (args.item.data.attributes.emoji) {
|
||||
this.isEmoji = true
|
||||
this.emoji = args.item.data.attributes.emoji
|
||||
}
|
||||
|
||||
// Store picked item
|
||||
this.pickedItem = args.item
|
||||
})
|
||||
},
|
||||
}
|
||||
</script>
|
||||
304
resources/js/components/Popups/ShareCreatePopup.vue
Normal file
304
resources/js/components/Popups/ShareCreatePopup.vue
Normal file
@@ -0,0 +1,304 @@
|
||||
<template>
|
||||
<PopupWrapper name="share-create">
|
||||
<!--Title-->
|
||||
<PopupHeader :title="$t('popup_share_create.title', { item: itemTypeTitle })" icon="share" />
|
||||
|
||||
<!--Content-->
|
||||
<PopupContent class="!overflow-initial">
|
||||
<!--Item Thumbnail-->
|
||||
<ThumbnailItem class="mb-5" :item="pickedItem" />
|
||||
|
||||
<!--Form to set sharing-->
|
||||
<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 }"
|
||||
>
|
||||
<AppInputText :title="$t('permission')" :error="errors[0]">
|
||||
<SelectInput
|
||||
v-model="shareOptions.permission"
|
||||
:options="$translateSelectOptions(permissionOptions)"
|
||||
:placeholder="$t('shared_form.placeholder_permission')"
|
||||
:isError="errors[0]"
|
||||
/>
|
||||
</AppInputText>
|
||||
</ValidationProvider>
|
||||
|
||||
<!--Password Switch-->
|
||||
<div>
|
||||
<AppInputSwitch
|
||||
:title="$t('password_protected')"
|
||||
: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 }"
|
||||
>
|
||||
<AppInputText :error="errors[0]" class="-mt-2">
|
||||
<input
|
||||
v-model="shareOptions.password"
|
||||
:class="{ '!border-rose-600': errors[0] }"
|
||||
type="text"
|
||||
class="focus-border-theme input-dark"
|
||||
:placeholder="$t('page_sign_in.placeholder_password')"
|
||||
/>
|
||||
</AppInputText>
|
||||
</ValidationProvider>
|
||||
</div>
|
||||
|
||||
<!--Expiration switch-->
|
||||
<div>
|
||||
<AppInputSwitch :title="$t('expiration')" :description="$t('popup.share.expiration_description')">
|
||||
<SwitchInput v-model="isExpiration" class="switch" :state="isExpiration" />
|
||||
</AppInputSwitch>
|
||||
|
||||
<!--Set expiration-->
|
||||
<AppInputText v-if="isExpiration" class="-mt-2">
|
||||
<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"
|
||||
>
|
||||
<SwitchInput v-model="isEmailSharing" class="switch" :state="isEmailSharing" />
|
||||
</AppInputSwitch>
|
||||
|
||||
<!--Emails-->
|
||||
<ValidationProvider
|
||||
v-if="isEmailSharing"
|
||||
tag="div"
|
||||
mode="passive"
|
||||
name="Email"
|
||||
rules="required"
|
||||
v-slot="{ errors }"
|
||||
class="-mt-2 mb-1"
|
||||
>
|
||||
<AppInputText :error="errors[0]" class="-mt-2" :is-last="true">
|
||||
<MultiEmailInput
|
||||
rules="required"
|
||||
v-model="shareOptions.emails"
|
||||
:label="$t('recipients')"
|
||||
:is-error="errors[0]"
|
||||
/>
|
||||
</AppInputText>
|
||||
</ValidationProvider>
|
||||
</div>
|
||||
</ValidationObserver>
|
||||
|
||||
<!--Copy generated link-->
|
||||
<AppInputText v-if="isGeneratedShared" :title="$t('get_your_link')" :is-last="true">
|
||||
<CopyShareLink :item="pickedItem" />
|
||||
</AppInputText>
|
||||
</PopupContent>
|
||||
|
||||
<!--Actions-->
|
||||
<PopupActions>
|
||||
<ButtonBase v-if="!isGeneratedShared" class="w-full" @click.native="$closePopup()" button-style="secondary">
|
||||
{{ $t('cancel') }}
|
||||
</ButtonBase>
|
||||
<ButtonBase
|
||||
class="w-full"
|
||||
@click.native="submitShareOptions"
|
||||
button-style="theme"
|
||||
:loading="isLoading"
|
||||
:disabled="isLoading"
|
||||
>
|
||||
{{ submitButtonText }}
|
||||
</ButtonBase>
|
||||
</PopupActions>
|
||||
</PopupWrapper>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import AppInputText from '../Forms/Layouts/AppInputText'
|
||||
import AppInputSwitch from '../Forms/Layouts/AppInputSwitch'
|
||||
import { ValidationProvider, ValidationObserver } from 'vee-validate/dist/vee-validate.full'
|
||||
import SelectBoxInput from '../Inputs/SelectBoxInput'
|
||||
import PopupWrapper from './Components/PopupWrapper'
|
||||
import PopupActions from './Components/PopupActions'
|
||||
import PopupContent from './Components/PopupContent'
|
||||
import PopupHeader from './Components/PopupHeader'
|
||||
import MultiEmailInput from '../Inputs/MultiEmailInput'
|
||||
import SwitchInput from '../Inputs/SwitchInput'
|
||||
import SelectInput from '../Inputs/SelectInput'
|
||||
import ThumbnailItem from '../UI/Entries/ThumbnailItem'
|
||||
import ActionButton from '../UI/Buttons/ActionButton'
|
||||
import CopyShareLink from '../Inputs/CopyShareLink'
|
||||
import ButtonBase from '../UI/Buttons/ButtonBase'
|
||||
import InfoBox from '../UI/Others/InfoBox'
|
||||
import { LinkIcon, MailIcon } from 'vue-feather-icons'
|
||||
import { required } from 'vee-validate/dist/rules'
|
||||
import { mapGetters } from 'vuex'
|
||||
import { events } from '../../bus'
|
||||
import axios from 'axios'
|
||||
|
||||
export default {
|
||||
name: 'ShareCreatePopup',
|
||||
components: {
|
||||
ValidationProvider,
|
||||
ValidationObserver,
|
||||
AppInputText,
|
||||
AppInputSwitch,
|
||||
SelectBoxInput,
|
||||
ThumbnailItem,
|
||||
ActionButton,
|
||||
PopupWrapper,
|
||||
PopupActions,
|
||||
PopupContent,
|
||||
PopupHeader,
|
||||
MultiEmailInput,
|
||||
SelectInput,
|
||||
SwitchInput,
|
||||
ButtonBase,
|
||||
CopyShareLink,
|
||||
MailIcon,
|
||||
required,
|
||||
LinkIcon,
|
||||
InfoBox,
|
||||
},
|
||||
computed: {
|
||||
...mapGetters(['permissionOptions', 'expirationList']),
|
||||
itemTypeTitle() {
|
||||
return this.pickedItem && this.pickedItem.data.type === 'folder'
|
||||
? this.$t('folder')
|
||||
: this.$t('file')
|
||||
},
|
||||
isFolder() {
|
||||
return this.pickedItem && this.pickedItem.data.type === 'folder'
|
||||
},
|
||||
submitButtonText() {
|
||||
return this.isGeneratedShared ? this.$t('awesome_iam_done') : this.$t('generate_link')
|
||||
},
|
||||
},
|
||||
watch: {
|
||||
isExpiration(val) {
|
||||
if (!val) this.shareOptions.expiration = undefined
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
isExpiration: false,
|
||||
isEmailSharing: false,
|
||||
shareOptions: {
|
||||
isPassword: false,
|
||||
expiration: undefined,
|
||||
password: undefined,
|
||||
permission: undefined,
|
||||
type: undefined,
|
||||
id: undefined,
|
||||
emails: undefined,
|
||||
},
|
||||
pickedItem: undefined,
|
||||
isGeneratedShared: false,
|
||||
isLoading: false,
|
||||
sharedViaEmail: false,
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
async submitShareOptions() {
|
||||
// If shared was generated, then close popup
|
||||
if (this.isGeneratedShared) {
|
||||
events.$emit('popup:close')
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// Validate fields
|
||||
const isValid = await this.$refs.shareForm.validate()
|
||||
|
||||
if (!isValid) return
|
||||
|
||||
this.isLoading = true
|
||||
|
||||
// Send request to get share link
|
||||
axios
|
||||
.post(`/api/share`, this.shareOptions)
|
||||
.then((response) => {
|
||||
// End loading
|
||||
this.isGeneratedShared = true
|
||||
|
||||
this.$store.commit('UPDATE_SHARED_ITEM', response.data)
|
||||
|
||||
this.pickedItem.data.relationships.shared = response.data
|
||||
})
|
||||
.catch(() => {
|
||||
events.$emit('alert:open', {
|
||||
title: this.$t('popup_error.title'),
|
||||
message: this.$t('popup_error.message'),
|
||||
})
|
||||
|
||||
// End loading
|
||||
this.isLoading = false
|
||||
})
|
||||
.finally(() => {
|
||||
this.isLoading = false
|
||||
})
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
events.$on('emailsInputValues', (emails) => (this.shareOptions.emails = emails))
|
||||
|
||||
// Show popup
|
||||
events.$on('popup:open', (args) => {
|
||||
if (args.name !== 'share-create') return
|
||||
|
||||
// Store picked item
|
||||
this.pickedItem = args.item
|
||||
|
||||
this.shareOptions.type = args.item.data.type
|
||||
this.shareOptions.id = args.item.data.id
|
||||
})
|
||||
|
||||
// Close popup
|
||||
events.$on('popup:close', () => {
|
||||
// Restore data
|
||||
setTimeout(() => {
|
||||
this.isGeneratedShared = false
|
||||
this.isExpiration = false
|
||||
this.isEmailSharing = false
|
||||
this.shareOptions = {
|
||||
isPassword: false,
|
||||
expiration: undefined,
|
||||
password: undefined,
|
||||
permission: undefined,
|
||||
type: undefined,
|
||||
id: undefined,
|
||||
emails: undefined,
|
||||
}
|
||||
}, 150)
|
||||
})
|
||||
},
|
||||
}
|
||||
</script>
|
||||
402
resources/js/components/Popups/ShareEditPopup.vue
Normal file
402
resources/js/components/Popups/ShareEditPopup.vue
Normal file
@@ -0,0 +1,402 @@
|
||||
<template>
|
||||
<PopupWrapper name="share-edit">
|
||||
<!--Title-->
|
||||
<PopupHeader :title="popupTitle" icon="share" />
|
||||
|
||||
<!--Qr Code-->
|
||||
<div v-if="pickedItem && activeSection === 'qr-code'">
|
||||
<PopupContent class="flex items-center justify-center">
|
||||
<div v-if="!qrCode" class="relative my-8">
|
||||
<Spinner />
|
||||
</div>
|
||||
<div v-if="qrCode" v-html="qrCode" class="my-5 overflow-hidden rounded-xl"></div>
|
||||
</PopupContent>
|
||||
|
||||
<PopupActions>
|
||||
<ButtonBase class="w-full" @click.native="showSection(undefined)" button-style="secondary">
|
||||
{{ $t('show_details') }}
|
||||
</ButtonBase>
|
||||
<ButtonBase class="w-full" @click.native="$closePopup()" button-style="theme">
|
||||
{{ $t('awesome_iam_done') }}
|
||||
</ButtonBase>
|
||||
</PopupActions>
|
||||
</div>
|
||||
|
||||
<!--Share via email-->
|
||||
<div v-if="pickedItem && activeSection === 'email-sharing'">
|
||||
<PopupContent>
|
||||
<!--Item Thumbnail-->
|
||||
<ThumbnailItem class="mb-4" :item="pickedItem" />
|
||||
|
||||
<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')"
|
||||
:is-error="errors[0]"
|
||||
/>
|
||||
</AppInputText>
|
||||
</ValidationProvider>
|
||||
</ValidationObserver>
|
||||
</PopupContent>
|
||||
|
||||
<PopupActions>
|
||||
<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"
|
||||
>
|
||||
{{ $t('send') }}
|
||||
</ButtonBase>
|
||||
</PopupActions>
|
||||
</div>
|
||||
|
||||
<!--Update sharing-->
|
||||
<div v-if="pickedItem && !activeSection">
|
||||
<PopupContent class="!overflow-initial">
|
||||
<!--Item Thumbnail-->
|
||||
<ThumbnailItem class="mb-5" :item="pickedItem" />
|
||||
|
||||
<!--Get share link-->
|
||||
<AppInputText :title="$t('get_your_link')">
|
||||
<CopyShareLink :item="pickedItem" />
|
||||
</AppInputText>
|
||||
|
||||
<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 }"
|
||||
>
|
||||
<AppInputText :title="$t('permission')" :error="errors[0]">
|
||||
<SelectInput
|
||||
v-model="shareOptions.permission"
|
||||
:options="$translateSelectOptions(permissionOptions)"
|
||||
:default="shareOptions.permission"
|
||||
:placeholder="$t('shared_form.placeholder_permission')"
|
||||
:isError="errors[0]"
|
||||
/>
|
||||
</AppInputText>
|
||||
</ValidationProvider>
|
||||
|
||||
<!--Password Switch-->
|
||||
<div>
|
||||
<AppInputSwitch
|
||||
:title="$t('password_protected')"
|
||||
: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
|
||||
"
|
||||
@click.native="changePassword"
|
||||
class="mb-6 -mt-4"
|
||||
>
|
||||
{{ $t('popup_share_edit.change_pass') }}
|
||||
</ActionButton>
|
||||
|
||||
<!--Set password-->
|
||||
<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"
|
||||
:class="{ '!border-rose-600': errors[0] }"
|
||||
type="text"
|
||||
class="focus-border-theme input-dark"
|
||||
:placeholder="$t('page_sign_in.placeholder_password')"
|
||||
/>
|
||||
</AppInputText>
|
||||
</ValidationProvider>
|
||||
</div>
|
||||
|
||||
<!--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>
|
||||
|
||||
<!--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"
|
||||
/>
|
||||
</AppInputText>
|
||||
</div>
|
||||
</ValidationObserver>
|
||||
</PopupContent>
|
||||
|
||||
<PopupActions>
|
||||
<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"
|
||||
>
|
||||
{{ $t('store_changes') }}
|
||||
</ButtonBase>
|
||||
</PopupActions>
|
||||
</div>
|
||||
</PopupWrapper>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { ValidationProvider, ValidationObserver } from 'vee-validate/dist/vee-validate.full'
|
||||
import MultiEmailInput from '../Inputs/MultiEmailInput'
|
||||
import SelectBoxInput from '../Inputs/SelectBoxInput'
|
||||
import CopyShareLink from '../Inputs/CopyShareLink'
|
||||
import PopupWrapper from './Components/PopupWrapper'
|
||||
import PopupActions from './Components/PopupActions'
|
||||
import PopupContent from './Components/PopupContent'
|
||||
import PopupHeader from './Components/PopupHeader'
|
||||
import SwitchInput from '../Inputs/SwitchInput'
|
||||
import SelectInput from '../Inputs/SelectInput'
|
||||
import ThumbnailItem from '../UI/Entries/ThumbnailItem'
|
||||
import ActionButton from '../UI/Buttons/ActionButton'
|
||||
import ButtonBase from '../UI/Buttons/ButtonBase'
|
||||
import AppInputSwitch from '../Forms/Layouts/AppInputSwitch'
|
||||
import AppInputText from '../Forms/Layouts/AppInputText'
|
||||
import { required } from 'vee-validate/dist/rules'
|
||||
import Spinner from '../UI/Others/Spinner'
|
||||
import { events } from '../../bus'
|
||||
import { mapGetters } from 'vuex'
|
||||
import axios from 'axios'
|
||||
|
||||
export default {
|
||||
name: 'ShareEditPopup',
|
||||
components: {
|
||||
ValidationProvider,
|
||||
ValidationObserver,
|
||||
MultiEmailInput,
|
||||
AppInputSwitch,
|
||||
SelectBoxInput,
|
||||
ThumbnailItem,
|
||||
CopyShareLink,
|
||||
ActionButton,
|
||||
PopupWrapper,
|
||||
PopupActions,
|
||||
AppInputText,
|
||||
PopupContent,
|
||||
PopupHeader,
|
||||
SelectInput,
|
||||
SwitchInput,
|
||||
ButtonBase,
|
||||
required,
|
||||
Spinner,
|
||||
},
|
||||
computed: {
|
||||
...mapGetters(['permissionOptions', 'expirationList', 'user']),
|
||||
popupTitle() {
|
||||
return (
|
||||
{
|
||||
'qr-code': this.$t('get_qr_code'),
|
||||
'email-sharing': this.$t('share_with_multiple_emails'),
|
||||
}[this.activeSection] || this.$t('popup_share_edit.title')
|
||||
)
|
||||
},
|
||||
isFolder() {
|
||||
return this.pickedItem && this.pickedItem.data.type === 'folder'
|
||||
},
|
||||
destroyButtonText() {
|
||||
return this.isConfirmedDestroy ? this.$t('popup_share_edit.confirm') : this.$t('popup_share_edit.stop')
|
||||
},
|
||||
destroyButtonStyle() {
|
||||
return this.isConfirmedDestroy ? 'danger-solid' : 'secondary'
|
||||
},
|
||||
},
|
||||
watch: {
|
||||
'shareOptions.expiration': function (val) {
|
||||
if (!val) {
|
||||
this.shareOptions.expiration = undefined
|
||||
}
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
activeSection: undefined,
|
||||
shareOptions: undefined,
|
||||
pickedItem: undefined,
|
||||
emails: undefined,
|
||||
qrCode: undefined,
|
||||
isConfirmedDestroy: false,
|
||||
canChangePassword: false,
|
||||
isMoreOptions: false,
|
||||
isDeleting: false,
|
||||
isLoading: false,
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
getQrCode() {
|
||||
axios
|
||||
.get(`/api/share/${this.shareOptions.token}/qr`)
|
||||
.then((response) => {
|
||||
this.qrCode = response.data
|
||||
})
|
||||
.catch(() => this.$isSomethingWrong())
|
||||
},
|
||||
showSection(section = undefined) {
|
||||
this.activeSection = section
|
||||
},
|
||||
changePassword() {
|
||||
this.canChangePassword = false
|
||||
},
|
||||
async sendViaEmail() {
|
||||
// Validate email field
|
||||
const isValid = await this.$refs.shareEmail.validate()
|
||||
|
||||
if (!isValid) return
|
||||
|
||||
this.isLoading = true
|
||||
|
||||
axios
|
||||
.post(`/api/share/${this.shareOptions.token}/email`, {
|
||||
emails: this.emails,
|
||||
})
|
||||
.catch(() => {
|
||||
this.$isSomethingWrong()
|
||||
})
|
||||
.finally(() => {
|
||||
this.isLoading = false
|
||||
this.$closePopup()
|
||||
})
|
||||
},
|
||||
async destroySharing() {
|
||||
// Set confirm button
|
||||
if (!this.isConfirmedDestroy) {
|
||||
this.isConfirmedDestroy = true
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// Start deleting spinner button
|
||||
this.isDeleting = true
|
||||
|
||||
// Send delete request
|
||||
await this.$store
|
||||
.dispatch('shareCancel', this.pickedItem)
|
||||
.catch(() => {
|
||||
// End deleting spinner button
|
||||
this.isDeleting = false
|
||||
})
|
||||
.finally(() => this.$closePopup())
|
||||
},
|
||||
async updateShareOptions() {
|
||||
// Validate fields
|
||||
const isValid = await this.$refs.shareForm.validate()
|
||||
|
||||
if (!isValid) return
|
||||
|
||||
this.isLoading = true
|
||||
|
||||
// Send request to get share link
|
||||
axios
|
||||
.post('/api/share/' + this.shareOptions.token, {
|
||||
permission: this.shareOptions.permission,
|
||||
protected: this.shareOptions.isProtected,
|
||||
expiration: this.shareOptions.expiration,
|
||||
password: this.shareOptions.password ? this.shareOptions.password : undefined,
|
||||
_method: 'patch',
|
||||
})
|
||||
.then((response) => {
|
||||
// Update shared data
|
||||
this.$store.commit('UPDATE_SHARED_ITEM', response.data)
|
||||
|
||||
events.$emit('popup:close')
|
||||
})
|
||||
.catch(() => {
|
||||
this.$isSomethingWrong()
|
||||
})
|
||||
.finally(() => {
|
||||
this.isLoading = false
|
||||
})
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
events.$on('emailsInputValues', (emails) => (this.emails = emails))
|
||||
|
||||
// Show popup
|
||||
events.$on('popup:open', (args) => {
|
||||
if (args.name !== 'share-edit') return
|
||||
|
||||
// Store picked item
|
||||
this.pickedItem = args.item
|
||||
|
||||
// Store shared options
|
||||
this.shareOptions = {
|
||||
id: args.item.data.relationships.shared.data.id,
|
||||
token: args.item.data.relationships.shared.data.attributes.token,
|
||||
expiration: args.item.data.relationships.shared.data.attributes.expire_in,
|
||||
isProtected: args.item.data.relationships.shared.data.attributes.protected,
|
||||
permission: args.item.data.relationships.shared.data.attributes.permission,
|
||||
password: undefined,
|
||||
}
|
||||
|
||||
if (args.section) this.activeSection = args.section
|
||||
|
||||
if (args.section === 'qr-code') this.getQrCode()
|
||||
|
||||
this.canChangePassword = args.item.data.relationships.shared.data.attributes.protected
|
||||
})
|
||||
|
||||
events.$on('popup:close', () => {
|
||||
// Reset data
|
||||
setTimeout(() => {
|
||||
this.isDeleting = false
|
||||
this.isConfirmedDestroy = false
|
||||
this.canChangePassword = false
|
||||
this.shareOptions = undefined
|
||||
this.pickedItem = undefined
|
||||
this.activeSection = undefined
|
||||
this.qrCode = undefined
|
||||
}, 150)
|
||||
})
|
||||
},
|
||||
}
|
||||
</script>
|
||||
Reference in New Issue
Block a user