UI improvements part 4

This commit is contained in:
Čarodej
2022-01-28 08:15:25 +01:00
parent f74bb7cec5
commit 0c71329dee
11 changed files with 395 additions and 218 deletions
+4
View File
@@ -161,6 +161,10 @@ export default {
@apply whitespace-nowrap overflow-ellipsis overflow-x-hidden block
}
input:-webkit-autofill {
transition-delay: 999999999999s;
}
[v-cloak],
[v-cloak] > * {
display: none
@@ -2,7 +2,7 @@
<div :class="{'dark:bg-dark-foreground bg-light-background': isClicked && highlight, 'dark:hover:bg-dark-foreground hover:bg-light-background': highlight}" class="flex items-center px-2.5 py-2 rounded-xl select-none border-2 border-transparent border-dashed" :draggable="canDrag" spellcheck="false">
<!--MultiSelecting for the mobile version-->
<CheckBox v-if="isMultiSelectMode" v-model="isClicked" class="mr-5"/>
<CheckBox v-if="isMultiSelectMode" v-model="isClicked" :is-clicked="isClicked" class="mr-5"/>
<!--Item thumbnail-->
<div class="w-16 relative">
@@ -105,6 +105,7 @@
return {
mobileMultiSelect: false,
itemName: undefined,
isSelected: false,
}
},
computed: {
@@ -5,12 +5,14 @@
<div class="input-area bg-light-background rounded-lg" :class="{'is-active': isOpen, 'is-error': isError}" @click="openMenu">
<!--If is selected-->
<div class="selected" v-if="selected">
<div class="selected w-full flex items-center" v-if="selected">
<div class="option-icon" v-if="selected.icon">
<user-icon v-if="selected.icon === 'user'" size="14" class="text-theme dark-text-theme" />
<edit2-icon v-if="selected.icon === 'user-edit'" size="14" class="text-theme dark-text-theme" />
<user-icon v-if="selected.icon === 'user'" size="14" class="vue-feather text-theme" />
<edit2-icon v-if="selected.icon === 'user-edit'" size="14" class="vue-feather text-theme" />
</div>
<span class="option-value">{{ selected.label }}</span>
<span class="whitespace-nowrap w-full inline-block overflow-hidden overflow-ellipsis option-value pl-2">
{{ selected.label }}
</span>
</div>
<!--If is empty-->
@@ -115,6 +117,8 @@
@import '/resources/sass/vuefilemanager/_variables';
@import '/resources/sass/vuefilemanager/_mixins';
/* TODO: refactor to the tailwind */
.select {
position: relative;
user-select: none;
@@ -203,21 +207,11 @@
width: 20px;
display: inline-block;
@include font-size(10);
svg {
margin-top: -4px;
vertical-align: middle;
line, path, circle {
color: inherit;
}
}
}
.option-value {
@include font-size(14);
font-weight: 700;
width: 100%;
vertical-align: middle;
&.placehoder {
@@ -1,19 +1,37 @@
<template>
<transition appear name="fade">
<li v-show="isActive" class="toaster-item" :class="item.type">
<div class="toaster-content-wrapper">
<span class="toaster-icon">
<check-icon v-if="item.type === 'success'" size="22" />
<x-icon v-if="item.type === 'danger'" size="22" />
</span>
<div class="toaster-content">
<p class="toaster-description">{{ item.message }}</p>
</div>
<div
v-if="isActive"
class="relative mt-4 p-4 md:w-96 w-full shadow-lg rounded-xl overflow-hidden backdrop-filter backdrop-blur-lg bg-opacity-80"
:class="{'dark:bg-2x-dark-foreground bg-red-50': isDanger, 'dark:bg-2x-dark-foreground bg-green-50': isSuccess}"
>
<!--Content-->
<div class="flex items-center justify-between">
<div class="flex items-center">
<div>
<check-icon v-if="isSuccess" size="22" class="vue-feather text-green-600" />
<x-icon v-if="isDanger" size="22" class="vue-feather text-red-600" />
</div>
<p
class="px-4 font-bold"
:class="{'text-green-600': isSuccess, 'text-red-600': isDanger}"
>
{{ item.message }}
</p>
</div>
<div @click="isActive = false" class="p-2 cursor-pointer">
<x-icon size="16" class="vue-feather dark:text-white text-black opacity-50" />
</div>
</div>
<div :class="{'success': item.type === 'success', 'danger': item.type === 'danger'}" class="progressbar">
<span></span>
<!--Progress bar-->
<div class="absolute bottom-0 left-0 right-0">
<span class="w-0 h-1 block bar-animation" :class="{'bg-green-400': isSuccess, 'bg-red-400': isDanger}"></span>
</div>
</li>
</div>
</transition>
</template>
@@ -28,143 +46,47 @@
props: [
'item'
],
computed: {
isDanger() {
return this.item.type === 'danger'
},
isSuccess() {
return this.item.type === 'success'
},
},
data() {
return {
isActive: 0
isActive: 1
}
},
created() {
this.isActive = 1
setTimeout(() => (this.isActive = 0), 6000)
}
}
</script>
<style lang="scss" scoped>
@import '/resources/sass/vuefilemanager/_variables';
@import '/resources/sass/vuefilemanager/_mixins';
.bar-animation {
animation: progressbar 6s linear;
}
.fade-enter-active,
.fade-leave-active {
transition: 0.3s ease;
}
.fade-enter,
.fade-leave-to {
opacity: 0;
@include transform(translateX(100%));
}
.toaster-content-wrapper {
display: flex;
align-items: center;
padding: 15px;
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.7);
}
.progressbar {
position: absolute;
bottom: 0;
left: 0;
right: 0;
opacity: 0.35;
span {
width: 0;
height: 3px;
display: block;
animation: progressbar 6s linear;
}
&.success span {
background: $theme;
@keyframes progressbar {
0% {
width: 0;
}
&.danger span {
background: $danger;
100% {
width: 100%;
}
}
}
@keyframes progressbar {
0% {
width: 0;
}
100% {
width: 100%;
}
}
.fade-enter-active,
.fade-leave-active {
transition: 0.3s ease;
}
.toaster-item {
max-width: 320px;
margin-top: 20px;
position: relative;
overflow: hidden;
display: block;
border-radius: 8px;
.toaster-description {
@include font-size(15);
font-weight: bold;
}
.toaster-icon {
height: 42px;
width: 42px;
display: inline-flex;
align-items: center;
justify-content: center;
padding: 0;
font-size: 20px;
margin-right: 10px;
}
&.success {
background: $theme_light;
line, polyline {
stroke: $theme;
}
.toaster-description {
color: $theme;
}
}
&.danger {
background: rgba($danger, 0.1);
line, polyline {
stroke: $danger;
}
.toaster-description {
color: $danger;
}
}
}
@media only screen and (max-width: 690px) {
.toaster-item {
margin-bottom: 0;
margin-top: 20px;
max-width: 100%;
}
.fade-enter,
.fade-leave-to {
opacity: 0;
@include transform(translateY(100%));
}
}
.dark {
.toaster-item {
&.success, &.danger {
background: $dark_mode_foreground;
}
}
}
.fade-enter,
.fade-leave-to {
opacity: 0;
transform: translateX(100%)
}
</style>
@@ -1,5 +1,5 @@
<template>
<div id="toaster-wrapper">
<div v-if="notifications.length > 0" class="fixed lg:bottom-8 bottom-4 lg:right-8 right-4 md:left-auto left-4 z-50">
<ToasterItem :item="item" v-for="(item, i) in notifications" :key="i"/>
</div>
</template>
@@ -22,40 +22,3 @@
}
}
</script>
<style lang="scss" scoped>
@import '/resources/sass/vuefilemanager/_variables';
@import '/resources/sass/vuefilemanager/_mixins';
.toaster-list {
transition: all 5s ease;
display: inline-block;
}
.toaster-list-enter,
.toaster-list-leave-to {
opacity: 0;
transform: translateY(-100%);
}
.toaster-list-leave-active {
position: absolute;
}
#toaster-wrapper {
position: fixed;
right: 30px;
bottom: 30px;
z-index: 90;
}
@media only screen and (max-width: 690px) {
#toaster-wrapper {
right: 15px;
left: 15px;
bottom: 15px;
}
}
</style>
+1 -1
View File
@@ -1,6 +1,6 @@
<template>
<div
class="2xl:w-3 md:w-2 w-1 block lg:mr-2 mr-1.5 relative cursor-pointer"
class="2xl:w-3 lg:w-2 block lg:mr-2 relative cursor-pointer"
:style="{height: bar.percentage + '%'}"
@mouseover="isVisible = true"
@mouseleave="isVisible = false"
+1 -1
View File
@@ -1,5 +1,5 @@
<template>
<div class="flex items-end justify-between sm:h-28 h-20">
<div class="lg:flex lg:items-end lg:justify-between grid grid-flow-col lg:gap-0 sm:gap-2 gap-1 items-end sm:h-28 h-20">
<!--Data bar-->
<Bar
v-for="(item, i) in data"
+14 -14
View File
@@ -25,7 +25,7 @@ const FunctionHelpers = {
if ((value === '' || value === ' ' || typeof value === 'object') && !allowEmpty) return
axios.post(this.$store.getters.api + route, {
axios.post(store.getters.api + route, {
[name]: value,
_method: 'patch'
})
@@ -47,7 +47,7 @@ const FunctionHelpers = {
formData.append(name, image)
formData.append('_method', 'PATCH')
axios.post(this.$store.getters.api + route, formData, {
axios.post(store.getters.api + route, formData, {
headers: {
'Content-Type': 'multipart/form-data',
}
@@ -138,7 +138,7 @@ const FunctionHelpers = {
}
Vue.prototype.$getImage = function (source) {
return source ? this.$store.getters.config.host + '/' + source : ''
return source ? store.getters.config.host + '/' + source : ''
}
Vue.prototype.$getCreditCardBrand = function (brand) {
@@ -163,7 +163,7 @@ const FunctionHelpers = {
// Push items to file queue
[...files].map(item => {
this.$store.commit('ADD_FILES_TO_QUEUE', {
store.commit('ADD_FILES_TO_QUEUE', {
parent_id: store.getters.currentFolder ? store.getters.currentFolder.data.id : '',
file: item,
path: '/' + item.webkitRelativePath
@@ -171,11 +171,11 @@ const FunctionHelpers = {
});
// Start uploading if uploading process isn't running
if (this.$store.getters.filesInQueueTotal == 0)
if (store.getters.filesInQueueTotal == 0)
this.$handleUploading(store.getters.fileQueue[0])
// Increase total files in upload bar
this.$store.commit('INCREASE_FILES_IN_QUEUES_TOTAL', files.length)
store.commit('INCREASE_FILES_IN_QUEUES_TOTAL', files.length)
}
Vue.prototype.$uploadDraggedFiles = async function (event, parent_id) {
@@ -191,18 +191,18 @@ const FunctionHelpers = {
// Push items to file queue
[...event.dataTransfer.items].map(item => {
this.$store.commit('ADD_FILES_TO_QUEUE', {
store.commit('ADD_FILES_TO_QUEUE', {
parent_id: parent_id ? parent_id : '',
file: item.getAsFile(),
})
});
// Start uploading if uploading process isn't running
if (this.$store.getters.filesInQueueTotal == 0)
this.$handleUploading(this.$store.getters.fileQueue[0])
if (store.getters.filesInQueueTotal == 0)
this.$handleUploading(store.getters.fileQueue[0])
// Increase total files in upload bar
this.$store.commit('INCREASE_FILES_IN_QUEUES_TOTAL', [...event.dataTransfer.items].length)
store.commit('INCREASE_FILES_IN_QUEUES_TOTAL', [...event.dataTransfer.items].length)
}
Vue.prototype.$handleUploading = async function (item) {
@@ -559,11 +559,11 @@ const FunctionHelpers = {
Vue.prototype.$openInDetailPanel = function (entry) {
// Dispatch load file info detail
this.$store.commit('CLIPBOARD_CLEAR')
this.$store.commit('ADD_ITEM_TO_CLIPBOARD', entry)
store.commit('CLIPBOARD_CLEAR')
store.commit('ADD_ITEM_TO_CLIPBOARD', entry)
// Show panel if is not open
this.$store.dispatch('fileInfoToggle', true)
store.dispatch('fileInfoToggle', true)
}
Vue.prototype.$openSpotlight = function (filter = undefined) {
@@ -571,7 +571,7 @@ const FunctionHelpers = {
}
Vue.prototype.$enableMultiSelectMode = function () {
this.$store.commit('TOGGLE_MULTISELECT_MODE')
store.commit('TOGGLE_MULTISELECT_MODE')
}
Vue.prototype.$showMobileMenu = function (name) {
+1 -1
View File
@@ -59,7 +59,7 @@
<router-view :user="user" />
</div>
<div id="loader" v-if="isLoading">
<Spinner></Spinner>
<Spinner />
</div>
</div>
</div>
-6
View File
@@ -18,12 +18,6 @@
transform: $effect;
}
@mixin no-yellow {
&:-webkit-autofill {
-webkit-box-shadow: 0 0 0 30px white inset;
}
}
@mixin blurred-image {
position: absolute;
left: 0;