mirror of
https://github.com/VueFileManager/vuefilemanager.git
synced 2026-04-21 17:12:15 +00:00
vue components refactoring
This commit is contained in:
52
resources/js/components/UI/Others/AlertBox.vue
Normal file
52
resources/js/components/UI/Others/AlertBox.vue
Normal file
@@ -0,0 +1,52 @@
|
||||
<template>
|
||||
<div
|
||||
class="mb-6 flex cursor-pointer items-center rounded-xl p-5 shadow-card"
|
||||
:class="{
|
||||
'dark:bg-green-700/30 bg-green-200': color === 'green',
|
||||
'dark:bg-rose-700/30 bg-rose-200': color === 'rose',
|
||||
}"
|
||||
>
|
||||
<refresh-cw-icon
|
||||
v-if="isLoading"
|
||||
size="18"
|
||||
class="vue-feather mr-4 shrink-0 animate-spin"
|
||||
:class="{
|
||||
'text-green-700 dark:text-green-500': color === 'green',
|
||||
'text-rose-700 dark:text-rose-500': color === 'rose',
|
||||
}"
|
||||
/>
|
||||
<alert-octagon-icon
|
||||
v-if="!isLoading"
|
||||
size="18"
|
||||
class="vue-feather mr-4 shrink-0"
|
||||
:class="{
|
||||
'text-green-700 dark:text-green-500': color === 'green',
|
||||
'text-rose-700 dark:text-rose-500': color === 'rose',
|
||||
}"
|
||||
/>
|
||||
<p
|
||||
class="text-sm text-green-700 dark:text-green-500"
|
||||
:class="{
|
||||
'text-green-700 dark:text-green-500': color === 'green',
|
||||
'text-rose-700 dark:text-rose-500': color === 'rose',
|
||||
}"
|
||||
>
|
||||
<slot />
|
||||
</p>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import {AlertOctagonIcon, RefreshCwIcon} from "vue-feather-icons";
|
||||
|
||||
export default {
|
||||
name: 'AlertBox',
|
||||
props: [
|
||||
'isLoading',
|
||||
'color',
|
||||
],
|
||||
components: {
|
||||
AlertOctagonIcon,
|
||||
RefreshCwIcon,
|
||||
}
|
||||
}
|
||||
</script>
|
||||
51
resources/js/components/UI/Others/CardNavigation.vue
Normal file
51
resources/js/components/UI/Others/CardNavigation.vue
Normal file
@@ -0,0 +1,51 @@
|
||||
<template>
|
||||
<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,
|
||||
}"
|
||||
>
|
||||
<div class="overflow-x-auto whitespace-nowrap">
|
||||
<router-link
|
||||
class="border-bottom-theme inline-block border-b-2 border-transparent px-4 py-5 text-sm font-bold"
|
||||
:class="{
|
||||
'text-theme': routeName === page.route,
|
||||
'text-gray-600 dark:text-gray-100': routeName !== page.route,
|
||||
}"
|
||||
v-for="(page, i) in pages"
|
||||
:to="{ name: page.route }"
|
||||
:key="i"
|
||||
replace
|
||||
>
|
||||
{{ page.title }}
|
||||
</router-link>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'CardNavigation',
|
||||
props: ['pages'],
|
||||
computed: {
|
||||
routeName() {
|
||||
return this.$route.name
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
fixedNav: false,
|
||||
}
|
||||
},
|
||||
created() {
|
||||
// Handle fixed mobile navigation
|
||||
window.addEventListener('scroll', () => {
|
||||
let card = document.getElementById('card-navigation')
|
||||
|
||||
this.fixedNav = card.getBoundingClientRect().top < 0
|
||||
})
|
||||
},
|
||||
}
|
||||
</script>
|
||||
46
resources/js/components/UI/Others/CookieDisclaimer.vue
Normal file
46
resources/js/components/UI/Others/CookieDisclaimer.vue
Normal file
@@ -0,0 +1,46 @@
|
||||
<template>
|
||||
<div
|
||||
v-if="isVisibleDisclaimer"
|
||||
class="fixed bottom-0 left-0 right-0 z-20 w-full rounded-tl-xl rounded-tr-lg bg-white p-4 shadow-xl dark:bg-dark-foreground sm:left-16 sm:right-auto sm:w-56 sm:p-3"
|
||||
>
|
||||
<span @click="closeDisclaimer" class="absolute -right-1 -top-1 cursor-pointer p-3">
|
||||
<x-icon size="10" />
|
||||
</span>
|
||||
<i18n path="cookie_disclaimer.description" tag="p" class="text-xs">
|
||||
<router-link :to="{ name: 'DynamicPage', params: { slug: 'cookie-policy' } }" class="text-theme text-xs">
|
||||
{{ $t('cookie_disclaimer.button') }}
|
||||
</router-link>
|
||||
</i18n>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { XIcon } from 'vue-feather-icons'
|
||||
import { mapGetters } from 'vuex'
|
||||
|
||||
export default {
|
||||
name: 'CookieDisclaimer',
|
||||
components: {
|
||||
XIcon,
|
||||
},
|
||||
computed: {
|
||||
...mapGetters(['config']),
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
isVisibleDisclaimer: false,
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
closeDisclaimer() {
|
||||
localStorage.setItem('isHiddenDisclaimer', 'true')
|
||||
|
||||
this.isVisibleDisclaimer = false
|
||||
},
|
||||
},
|
||||
created() {
|
||||
this.isVisibleDisclaimer =
|
||||
this.config.installation === 'installation-done' && !localStorage.getItem('isHiddenDisclaimer')
|
||||
},
|
||||
}
|
||||
</script>
|
||||
79
resources/js/components/UI/Others/DragUI.vue
Normal file
79
resources/js/components/UI/Others/DragUI.vue
Normal file
@@ -0,0 +1,79 @@
|
||||
<template>
|
||||
<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>
|
||||
import TitlePreview from '../Labels/TitlePreview'
|
||||
import { mapGetters } from 'vuex'
|
||||
import { events } from '../../../bus'
|
||||
|
||||
export default {
|
||||
name: 'DragUI',
|
||||
components: {
|
||||
TitlePreview,
|
||||
},
|
||||
computed: {
|
||||
...mapGetters(['clipboard']),
|
||||
title() {
|
||||
let filesLength = this.clipboard.length,
|
||||
hasDraggedItem = this.clipboard.includes(this.draggedItem)
|
||||
|
||||
// Title for multiple selected items
|
||||
if (filesLength > 1 && hasDraggedItem) {
|
||||
return this.$t('selected_multiple')
|
||||
}
|
||||
|
||||
// Title for single item
|
||||
if ((filesLength < 2 || !hasDraggedItem) && this.draggedItem) {
|
||||
return this.draggedItem.data.attributes.name
|
||||
}
|
||||
},
|
||||
subtitle() {
|
||||
let filesLength = this.clipboard.length,
|
||||
hasDraggedItem = this.clipboard.includes(this.draggedItem)
|
||||
|
||||
// Subtitle for multiple selected items
|
||||
if (filesLength > 1 && hasDraggedItem) {
|
||||
return filesLength + ' ' + this.$tc('items', filesLength)
|
||||
}
|
||||
|
||||
if ((filesLength < 2 || !hasDraggedItem) && this.draggedItem) {
|
||||
// Subtitle for single folder
|
||||
if (this.draggedItem.data.type === 'folder') {
|
||||
return this.draggedItem.items == 0
|
||||
? this.$t('empty')
|
||||
: this.$tc('folder.item_counts', this.draggedItem.items)
|
||||
}
|
||||
|
||||
// Subtitle for single file
|
||||
if (this.draggedItem.data.type !== 'folder' && this.draggedItem.data.attributes.mimetype) {
|
||||
return '.' + this.draggedItem.data.attributes.mimetype
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
isVisible: false,
|
||||
draggedItem: undefined,
|
||||
}
|
||||
},
|
||||
created() {
|
||||
events.$on('dragstart', (data) => {
|
||||
this.draggedItem = data
|
||||
|
||||
setTimeout(() => {
|
||||
this.isVisible = true
|
||||
}, 100)
|
||||
})
|
||||
|
||||
events.$on('drop', () => (this.isVisible = false))
|
||||
},
|
||||
}
|
||||
</script>
|
||||
90
resources/js/components/UI/Others/ImageMetaData.vue
Normal file
90
resources/js/components/UI/Others/ImageMetaData.vue
Normal file
@@ -0,0 +1,90 @@
|
||||
<template>
|
||||
<div>
|
||||
<div class="flex items-center justify-between pt-0.5 pb-2" v-if="clipboard.data.attributes.date_time_original">
|
||||
<b class="font-bold text-sm">{{ $t('time_data') }}</b>
|
||||
<b class="font-bold text-sm">{{ clipboard.data.attributes.date_time_original }}</b>
|
||||
</div>
|
||||
|
||||
<div class="flex items-center justify-between py-2" v-if="clipboard.data.attributes.artist">
|
||||
<b class="font-bold text-sm">{{ $t('author') }}</b>
|
||||
<b class="font-bold text-sm">{{ clipboard.data.attributes.artist }}</b>
|
||||
</div>
|
||||
|
||||
<div class="flex items-center justify-between py-2" v-if="clipboard.data.attributes.width && clipboard.data.attributes.height">
|
||||
<b class="font-bold text-sm">{{ $t('dimension') }}</b>
|
||||
<b class="font-bold text-sm">{{ clipboard.data.attributes.width }}x{{ clipboard.data.attributes.height }}</b>
|
||||
</div>
|
||||
|
||||
<div class="flex items-center justify-between py-2" v-if="clipboard.data.attributes.x_resolution && clipboard.data.attributes.y_resolution">
|
||||
<b class="font-bold text-sm">{{ $t('resolution') }}</b>
|
||||
<b class="font-bold text-sm">{{ clipboard.data.attributes.x_resolution }}x{{ clipboard.data.attributes.y_resolution }}</b>
|
||||
</div>
|
||||
|
||||
<div class="flex items-center justify-between py-2" v-if="clipboard.data.attributes.color_space">
|
||||
<b class="font-bold text-sm"> {{ $t('color_space') }}</b>
|
||||
<b class="font-bold text-sm">{{ clipboard.data.attributes.color_space }}</b>
|
||||
</div>
|
||||
|
||||
<div class="flex items-center justify-between py-2" v-if="clipboard.data.attributes.make">
|
||||
<b class="font-bold text-sm">{{ $t('make') }}</b>
|
||||
<b class="font-bold text-sm">{{ clipboard.data.attributes.make }}</b>
|
||||
</div>
|
||||
|
||||
<div class="flex items-center justify-between py-2" v-if="clipboard.data.attributes.model">
|
||||
<b class="font-bold text-sm">{{ $t('model') }}</b>
|
||||
<b class="font-bold text-sm">{{ clipboard.data.attributes.model }}</b>
|
||||
</div>
|
||||
|
||||
<div class="flex items-center justify-between py-2" v-if="clipboard.data.attributes.aperture_value">
|
||||
<b class="font-bold text-sm">{{ $t('aperture_value') }}</b>
|
||||
<b class="font-bold text-sm"> {{ clipboard.data.attributes.aperture_value }} </b>
|
||||
</div>
|
||||
|
||||
<div class="flex items-center justify-between py-2" v-if="clipboard.data.attributes.exposure_time">
|
||||
<b class="font-bold text-sm">{{ $t('exposure') }}</b>
|
||||
<b class="font-bold text-sm">{{ clipboard.data.attributes.exposure_time }}</b>
|
||||
</div>
|
||||
|
||||
<div class="flex items-center justify-between py-2" v-if="clipboard.data.attributes.focal_length">
|
||||
<b class="font-bold text-sm">{{ $t('focal') }}</b>
|
||||
<b class="font-bold text-sm">{{ clipboard.data.attributes.focal_length }}</b>
|
||||
</div>
|
||||
|
||||
<div class="flex items-center justify-between py-2" v-if="clipboard.data.attributes.iso">
|
||||
<b class="font-bold text-sm">{{ $t('iso') }}</b>
|
||||
<b class="font-bold text-sm">{{ clipboard.data.attributes.iso }}</b>
|
||||
</div>
|
||||
|
||||
<div class="flex items-center justify-between py-2" v-if="clipboard.data.attributes.aperture_f_number">
|
||||
<b class="font-bold text-sm">{{ $t('aperature') }}</b>
|
||||
<b class="font-bold text-sm">{{ clipboard.data.attributes.aperture_f_number }}</b>
|
||||
</div>
|
||||
|
||||
<div class="flex items-center justify-between py-2" v-if="clipboard.data.attributes.ccd_width">
|
||||
<b class="font-bold text-sm">{{ $t('camera_lens') }}</b>
|
||||
<b class="font-bold text-sm">{{ clipboard.data.attributes.ccd_width }}</b>
|
||||
</div>
|
||||
|
||||
<div class="flex items-center justify-between py-2" v-if="clipboard.data.attributes.longitude">
|
||||
<b class="font-bold text-sm">{{ $t('longitude') }}</b>
|
||||
<b class="font-bold text-sm">{{ clipboard.data.attributes.longitude }}</b>
|
||||
</div>
|
||||
|
||||
<div class="flex items-center justify-between py-2" v-if="clipboard.data.attributes.latitude">
|
||||
<b class="font-bold text-sm">{{ $t('latitude') }}</b>
|
||||
<b class="font-bold text-sm">{{ clipboard.data.attributes.latitude }}</b>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
||||
export default {
|
||||
name: 'ImageMetaData',
|
||||
computed: {
|
||||
clipboard() {
|
||||
return this.$store.getters.clipboard[0].data.relationships.exif
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
112
resources/js/components/UI/Others/InfoBox.vue
Normal file
112
resources/js/components/UI/Others/InfoBox.vue
Normal file
@@ -0,0 +1,112 @@
|
||||
<template>
|
||||
<div class="info-box" :class="type">
|
||||
<slot />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'InfoBox',
|
||||
props: ['type'],
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@import '../../../../sass/vuefilemanager/variables';
|
||||
@import '../../../../sass/vuefilemanager/mixins';
|
||||
|
||||
.info-box {
|
||||
padding: 20px;
|
||||
border-radius: 10px;
|
||||
margin-bottom: 32px;
|
||||
background: $light_background;
|
||||
text-align: left;
|
||||
|
||||
&.error {
|
||||
background: rgba($danger, 0.1);
|
||||
|
||||
p,
|
||||
a {
|
||||
color: $danger;
|
||||
}
|
||||
|
||||
a {
|
||||
text-decoration: underline;
|
||||
}
|
||||
}
|
||||
|
||||
p {
|
||||
font-size: 15px;
|
||||
line-height: 1.6;
|
||||
word-break: break-word;
|
||||
font-weight: 600;
|
||||
|
||||
/deep/ a {
|
||||
font-size: 15px;
|
||||
}
|
||||
|
||||
/deep/ b {
|
||||
font-size: 15px;
|
||||
font-weight: 700;
|
||||
}
|
||||
}
|
||||
|
||||
b {
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
a {
|
||||
font-weight: 700;
|
||||
@include font-size(15);
|
||||
line-height: 1.6;
|
||||
}
|
||||
|
||||
ul {
|
||||
margin-top: 15px;
|
||||
display: block;
|
||||
|
||||
li {
|
||||
display: block;
|
||||
|
||||
a {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@media only screen and (max-width: 690px) {
|
||||
.info-box {
|
||||
padding: 15px;
|
||||
}
|
||||
}
|
||||
|
||||
.dark {
|
||||
.info-box {
|
||||
background: $dark_mode_foreground;
|
||||
|
||||
&.error {
|
||||
background: rgba($danger, 0.1);
|
||||
|
||||
p,
|
||||
a {
|
||||
color: $danger;
|
||||
}
|
||||
|
||||
a {
|
||||
text-decoration: underline;
|
||||
}
|
||||
}
|
||||
|
||||
p {
|
||||
color: $dark_mode_text_primary;
|
||||
}
|
||||
|
||||
ul {
|
||||
li {
|
||||
color: $dark_mode_text_primary;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
72
resources/js/components/UI/Others/MemberAvatar.vue
Normal file
72
resources/js/components/UI/Others/MemberAvatar.vue
Normal file
@@ -0,0 +1,72 @@
|
||||
<template>
|
||||
<div class="shrink-0 grow-0">
|
||||
<img
|
||||
:style="{ width: size + 'px', height: size + 'px' }"
|
||||
v-if="member.data.attributes.avatar"
|
||||
:src="avatar"
|
||||
:class="[
|
||||
borderRadius,
|
||||
{
|
||||
'border-3 border-white dark:border-dark-background': isBorder,
|
||||
},
|
||||
]"
|
||||
class="object-cover mx-auto"
|
||||
/>
|
||||
<div
|
||||
v-else
|
||||
class="flex items-center justify-center mx-auto"
|
||||
:class="[
|
||||
borderRadius,
|
||||
{
|
||||
'border-3 border-white dark:border-dark-background': isBorder,
|
||||
'dark:bg-4x-dark-foreground bg-light-background': !member.data.attributes.color,
|
||||
},
|
||||
]"
|
||||
:style="{
|
||||
width: size + 'px',
|
||||
height: size + 'px',
|
||||
background: member.data.attributes.color ? member.data.attributes.color : '',
|
||||
}"
|
||||
>
|
||||
<span :class="fontSize" class="font-extrabold uppercase text-white">
|
||||
{{ letter }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
export default {
|
||||
name: 'MemberAvatar',
|
||||
props: ['isBorder', 'member', 'size'],
|
||||
computed: {
|
||||
letter() {
|
||||
let string = this.member.data.attributes.name
|
||||
? this.member.data.attributes.name
|
||||
: this.member.data.attributes.email
|
||||
|
||||
return string.substr(0, 1)
|
||||
},
|
||||
borderRadius() {
|
||||
return this.size > 32 ? 'rounded-xl' : 'rounded-lg'
|
||||
},
|
||||
fontSize() {
|
||||
if (this.size > 42) {
|
||||
return 'text-lg'
|
||||
} else if (this.size > 32) {
|
||||
return 'text-base'
|
||||
} else {
|
||||
return 'text-sm'
|
||||
}
|
||||
},
|
||||
avatar() {
|
||||
if (this.size >= 52) {
|
||||
return this.member.data.attributes.avatar.md
|
||||
} else if (this.size > 32) {
|
||||
return this.member.data.attributes.avatar.sm
|
||||
} else {
|
||||
return this.member.data.attributes.avatar.xs
|
||||
}
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
44
resources/js/components/UI/Others/ProgressBar.vue
Normal file
44
resources/js/components/UI/Others/ProgressBar.vue
Normal file
@@ -0,0 +1,44 @@
|
||||
<template>
|
||||
<div class="progress-bar">
|
||||
<span class="bg-theme" :style="{ width: progress + '%' }"></span>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'ProgressBar',
|
||||
props: ['progress'],
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
@import '../../../../sass/vuefilemanager/variables';
|
||||
@import '../../../../sass/vuefilemanager/mixins';
|
||||
|
||||
.progress-bar {
|
||||
width: 100%;
|
||||
height: 5px;
|
||||
background: $light_background;
|
||||
margin-top: 6px;
|
||||
border-radius: 10px;
|
||||
|
||||
span {
|
||||
display: block;
|
||||
height: 100%;
|
||||
border-radius: 10px;
|
||||
max-width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.dark {
|
||||
.progress-bar {
|
||||
background: $dark_mode_foreground;
|
||||
}
|
||||
}
|
||||
|
||||
@media only screen and (min-width: 680px) {
|
||||
.dark .progress-bar {
|
||||
background: $dark_mode_foreground;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
44
resources/js/components/UI/Others/Spinner.vue
Normal file
44
resources/js/components/UI/Others/Spinner.vue
Normal file
@@ -0,0 +1,44 @@
|
||||
<template>
|
||||
<div id="loading-bar-spinner" class="spinner">
|
||||
<div class="spinner-icon border-top-theme border-left-theme"></div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'Spinner',
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
@import '../../../../sass/vuefilemanager/variables';
|
||||
@import '../../../../sass/vuefilemanager/mixins';
|
||||
|
||||
#loading-bar-spinner.spinner {
|
||||
left: 50%;
|
||||
margin-left: -20px;
|
||||
top: 50%;
|
||||
margin-top: -20px;
|
||||
position: absolute;
|
||||
z-index: 19 !important;
|
||||
animation: loading-bar-spinner 400ms linear infinite;
|
||||
}
|
||||
|
||||
#loading-bar-spinner.spinner .spinner-icon {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
border: solid 4px transparent;
|
||||
//border-top-color: $theme !important;
|
||||
//border-left-color: $theme !important;
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
@keyframes loading-bar-spinner {
|
||||
0% {
|
||||
transform: rotate(0deg);
|
||||
}
|
||||
100% {
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
131
resources/js/components/UI/Others/UploadProgress.vue
Normal file
131
resources/js/components/UI/Others/UploadProgress.vue
Normal file
@@ -0,0 +1,131 @@
|
||||
<template>
|
||||
<transition name="info-panel">
|
||||
<div v-if="fileQueue.length > 0" class="upload-progress">
|
||||
<div class="progress-title">
|
||||
<!--Is processing-->
|
||||
<span v-if="isProcessingFile" class="flex items-center justify-center">
|
||||
<refresh-cw-icon size="12" class="sync-alt text-theme" />
|
||||
{{ $t('uploading.processing_file') }}
|
||||
</span>
|
||||
|
||||
<!--Multi file upload-->
|
||||
<span v-if="!isProcessingFile && fileQueue.length > 0">
|
||||
{{
|
||||
$t('uploading.progress', {
|
||||
current: filesInQueueUploaded,
|
||||
total: filesInQueueTotal,
|
||||
progress: uploadingProgress,
|
||||
})
|
||||
}}
|
||||
</span>
|
||||
</div>
|
||||
<div class="progress-wrapper">
|
||||
<ProgressBar :progress="uploadingProgress" />
|
||||
<span @click="cancelUpload" :title="$t('uploading.cancel')" class="cancel-icon">
|
||||
<x-icon size="16" @click="cancelUpload" class="hover-text-theme"></x-icon>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</transition>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import ProgressBar from './ProgressBar'
|
||||
import { RefreshCwIcon, XIcon } from 'vue-feather-icons'
|
||||
import { mapGetters } from 'vuex'
|
||||
import { events } from '../../../bus'
|
||||
|
||||
export default {
|
||||
name: 'UploadProgress',
|
||||
components: {
|
||||
RefreshCwIcon,
|
||||
ProgressBar,
|
||||
XIcon,
|
||||
},
|
||||
computed: {
|
||||
...mapGetters([
|
||||
'filesInQueueUploaded',
|
||||
'filesInQueueTotal',
|
||||
'uploadingProgress',
|
||||
'isProcessingFile',
|
||||
'fileQueue',
|
||||
]),
|
||||
},
|
||||
methods: {
|
||||
cancelUpload() {
|
||||
events.$emit('cancel-upload')
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
@import '../../../../sass/vuefilemanager/variables';
|
||||
@import '../../../../sass/vuefilemanager/mixins';
|
||||
|
||||
.sync-alt {
|
||||
animation: spin 1s linear infinite;
|
||||
margin-right: 5px;
|
||||
|
||||
polyline,
|
||||
path {
|
||||
color: inherit;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes spin {
|
||||
0% {
|
||||
transform: rotate(0);
|
||||
}
|
||||
100% {
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
}
|
||||
|
||||
.info-panel-enter-active,
|
||||
.info-panel-leave-active {
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.info-panel-enter,
|
||||
.info-panel-leave-to {
|
||||
opacity: 0;
|
||||
transform: translateY(-100%);
|
||||
}
|
||||
|
||||
.upload-progress {
|
||||
width: 100%;
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
|
||||
.progress-wrapper {
|
||||
display: flex;
|
||||
|
||||
.cancel-icon {
|
||||
cursor: pointer;
|
||||
padding: 0 7px 0 13px;
|
||||
|
||||
&:hover {
|
||||
line {
|
||||
color: inherit;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.progress-title {
|
||||
font-weight: 700;
|
||||
text-align: center;
|
||||
|
||||
span {
|
||||
@include font-size(14);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.dark {
|
||||
.progress-bar {
|
||||
background: $dark_mode_foreground;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
39
resources/js/components/UI/Others/UserHeadline.vue
Normal file
39
resources/js/components/UI/Others/UserHeadline.vue
Normal file
@@ -0,0 +1,39 @@
|
||||
<template>
|
||||
<div class="flex items-center justify-between">
|
||||
<div class="flex items-center leading-none">
|
||||
<MemberAvatar :size="52" :is-border="false" :member="user" />
|
||||
<div class="pl-4">
|
||||
<b class="mb-1 block font-bold leading-none">
|
||||
{{ user.data.relationships.settings.data.attributes.name }}
|
||||
</b>
|
||||
<span class="text-theme text-sm font-semibold leading-none">
|
||||
{{ user.data.attributes.email }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<NotificationBell @click.native="openNotificationPopup" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import MemberAvatar from './MemberAvatar'
|
||||
import NotificationBell from '../../Notifications/Components/NotificationBell'
|
||||
import { events } from '../../../bus'
|
||||
import { mapGetters } from 'vuex'
|
||||
|
||||
export default {
|
||||
name: 'UserHeadline',
|
||||
components: {
|
||||
NotificationBell,
|
||||
MemberAvatar,
|
||||
},
|
||||
computed: {
|
||||
...mapGetters(['user']),
|
||||
},
|
||||
methods: {
|
||||
openNotificationPopup() {
|
||||
events.$emit('popup:open', { name: 'notifications-mobile' })
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
77
resources/js/components/UI/Others/Vignette.vue
Normal file
77
resources/js/components/UI/Others/Vignette.vue
Normal file
@@ -0,0 +1,77 @@
|
||||
<template>
|
||||
<transition name="vignette">
|
||||
<div
|
||||
v-if="isVisible"
|
||||
class="vignette dark:bg-2x-dark-background bg-dark-background bg-opacity-[0.35] dark:bg-opacity-[0.70]"
|
||||
@click="closePopup"
|
||||
></div>
|
||||
</transition>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { events } from '../../../bus'
|
||||
import { mapGetters } from 'vuex'
|
||||
|
||||
export default {
|
||||
name: 'Vignette',
|
||||
computed: {
|
||||
...mapGetters(['processingPopup']),
|
||||
isVisible() {
|
||||
return this.processingPopup || this.isVisibleVignette
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
isVisibleVignette: false,
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
closePopup() {
|
||||
events.$emit('popup:close')
|
||||
events.$emit('spotlight:hide')
|
||||
events.$emit('mobile-menu:hide')
|
||||
},
|
||||
},
|
||||
created() {
|
||||
// Show vignette
|
||||
events.$on('popup:open', () => (this.isVisibleVignette = true))
|
||||
events.$on('alert:open', () => (this.isVisibleVignette = true))
|
||||
events.$on('success:open', () => (this.isVisibleVignette = true))
|
||||
events.$on('confirm:open', () => (this.isVisibleVignette = true))
|
||||
|
||||
// Hide vignette
|
||||
events.$on('popup:close', () => (this.isVisibleVignette = false))
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@import '../../../../sass/vuefilemanager/variables';
|
||||
@import '../../../../sass/vuefilemanager/mixins';
|
||||
|
||||
.vignette {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
right: 0;
|
||||
left: 0;
|
||||
bottom: 0;
|
||||
z-index: 40;
|
||||
}
|
||||
|
||||
.vignette-enter-active {
|
||||
animation: vignette-in 0.15s linear;
|
||||
}
|
||||
|
||||
.vignette-leave-active {
|
||||
animation: vignette-in 0.15s cubic-bezier(0.4, 0, 1, 1) reverse;
|
||||
}
|
||||
|
||||
@keyframes vignette-in {
|
||||
0% {
|
||||
opacity: 0;
|
||||
}
|
||||
100% {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user