added prettier

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

View File

@@ -1,62 +1,47 @@
<template>
<div class="relative cursor-pointer">
<input
ref="file"
type="file"
@change="showImagePreview($event)"
class="absolute opacity-0 top-0 bottom-0 left-0 right-0 w-full z-10 cursor-pointer"
/>
<img
v-if="imagePreview"
ref="image"
:src="imagePreview"
class="md:w-16 w-14 md:h-16 h-14 object-cover rounded-xl relative z-0 shadow-lg cursor-pointer"
alt="avatar"
/>
<input ref="file" type="file" @change="showImagePreview($event)" class="absolute top-0 bottom-0 left-0 right-0 z-10 w-full cursor-pointer opacity-0" />
<img v-if="imagePreview" ref="image" :src="imagePreview" class="relative z-0 h-14 w-14 cursor-pointer rounded-xl object-cover shadow-lg md:h-16 md:w-16" alt="avatar" />
</div>
</template>
<script>
export default {
name: 'AvatarInput',
props: [
'avatar',
],
data() {
return {
imagePreview: undefined
}
},
watch: {
imagePreview(val) {
this.$store.commit('UPDATE_AVATAR', val)
}
},
methods: {
showImagePreview(event) {
let imgPath = event.target.files[0].name,
extension = imgPath
.substring(imgPath.lastIndexOf('.') + 1)
.toLowerCase()
export default {
name: 'AvatarInput',
props: ['avatar'],
data() {
return {
imagePreview: undefined,
}
},
watch: {
imagePreview(val) {
this.$store.commit('UPDATE_AVATAR', val)
},
},
methods: {
showImagePreview(event) {
let imgPath = event.target.files[0].name,
extension = imgPath.substring(imgPath.lastIndexOf('.') + 1).toLowerCase()
if (['png', 'jpg', 'jpeg'].includes(extension)) {
let file = event.target.files[0],
reader = new FileReader()
if (['png', 'jpg', 'jpeg'].includes(extension)) {
let file = event.target.files[0],
reader = new FileReader()
reader.onload = () => (this.imagePreview = reader.result)
reader.onload = () => (this.imagePreview = reader.result)
reader.readAsDataURL(file)
reader.readAsDataURL(file)
// Update user avatar
this.$updateImage('/user/settings', 'avatar', event.target.files[0])
} else {
alert(this.$t('validation_errors.wrong_image'))
}
}
},
created() {
// If there is default image then load
if (this.avatar) this.imagePreview = this.avatar
}
}
// Update user avatar
this.$updateImage('/user/settings', 'avatar', event.target.files[0])
} else {
alert(this.$t('validation_errors.wrong_image'))
}
},
},
created() {
// If there is default image then load
if (this.avatar) this.imagePreview = this.avatar
},
}
</script>

View File

@@ -1,28 +1,21 @@
<template>
<div @click="copyUrl" class="flex items-center relative">
<input ref="sel" :value="str" :id="id" type="text" class="pr-10 focus-border-theme input-dark" readonly>
<div @click="copyUrl" class="relative flex items-center">
<input ref="sel" :value="str" :id="id" type="text" class="focus-border-theme input-dark pr-10" readonly />
<!--Copy icon-->
<!--Copy icon-->
<div class="absolute right-0 px-4">
<copy-icon v-if="! isCopiedLink" size="16" class="cursor-pointer hover-text-theme vue-feather"/>
<check-icon v-if="isCopiedLink" size="16" class="cursor-pointer text-theme vue-feather"/>
<copy-icon v-if="!isCopiedLink" size="16" class="hover-text-theme vue-feather cursor-pointer" />
<check-icon v-if="isCopiedLink" size="16" class="text-theme vue-feather cursor-pointer" />
</div>
</div>
</template>
<script>
import {
CopyIcon,
CheckIcon,
SendIcon
} from 'vue-feather-icons'
import { CopyIcon, CheckIcon, SendIcon } from 'vue-feather-icons'
export default {
name: 'CopyInput',
props: [
'size',
'str',
],
props: ['size', 'str'],
components: {
CheckIcon,
CopyIcon,
@@ -31,12 +24,11 @@ export default {
data() {
return {
isCopiedLink: false,
id: 'link-input-' + Math.floor(Math.random() * 10000000),
id: 'link-input-' + Math.floor(Math.random() * 10000000),
}
},
methods: {
copyUrl() {
// Get input value
let copyText = document.getElementById(this.id)
@@ -54,7 +46,7 @@ export default {
setTimeout(() => {
this.isCopiedLink = false
}, 1000)
}
}
},
},
}
</script>

View File

@@ -1,47 +1,63 @@
<template>
<div class="flex items-center relative">
<input ref="sel" :value="item.data.relationships.shared.data.attributes.link" :id="id" type="text" class="pr-16 py-2 pl-3 text-sm focus-border-theme w-full dark:bg-2x-dark-foreground bg-light-background rounded-lg appearance-none border-transparent font-bold border" readonly>
<div class="relative flex items-center">
<input
ref="sel"
:value="item.data.relationships.shared.data.attributes.link"
:id="id"
type="text"
class="focus-border-theme w-full appearance-none rounded-lg border border-transparent bg-light-background py-2 pr-16 pl-3 text-sm font-bold dark:bg-2x-dark-foreground"
readonly
/>
<!--Copy icon-->
<div class="flex items-center">
<!--Copy icon-->
<div class="flex items-center">
<div @click="copyUrl" class="absolute right-9 p-1">
<copy-icon v-if="! isCopiedLink" size="14" class="cursor-pointer hover-text-theme vue-feather"/>
<check-icon v-if="isCopiedLink" size="14" class="cursor-pointer hover-text-theme vue-feather"/>
<copy-icon v-if="!isCopiedLink" size="14" class="hover-text-theme vue-feather cursor-pointer" />
<check-icon v-if="isCopiedLink" size="14" class="hover-text-theme vue-feather cursor-pointer" />
</div>
<div @click.stop.prevent="moreOptions" class="absolute right-2.5 p-1">
<more-horizontal-icon size="14" class="cursor-pointer hover-text-theme vue-feather" />
<more-horizontal-icon size="14" class="hover-text-theme vue-feather cursor-pointer" />
</div>
</div>
<!--Hidden options-->
<ul v-if="isOpenedMoreOptions" class="shadow-xl rounded-lg absolute top-12 left-0 right-0 z-10 overflow-y-auto overflow-x-hidden select-none">
<li @click="getQrCode" class="flex items-center py-2.5 px-5 block cursor-pointer dark:bg-2x-dark-foreground dark:hover:bg-4x-dark-foreground hover:bg-light-background bg-white">
<div class="w-8">
<camera-icon size="14" />
</div>
<span class="text-sm font-bold">
{{ $t('Get QR Code') }}
</span>
</li>
<li @click="sendViaEmail" class="flex items-center py-2.5 px-5 block cursor-pointer dark:bg-2x-dark-foreground dark:hover:bg-4x-dark-foreground hover:bg-light-background bg-white">
<div class="w-8">
<send-icon size="14" />
</div>
<span class="text-sm font-bold">
{{ $t('sharelink.share_via_email') }}
</span>
</li>
<li @click="copyIframe" class="flex items-center py-2.5 px-5 block cursor-pointer dark:bg-2x-dark-foreground dark:hover:bg-4x-dark-foreground hover:bg-light-background bg-white">
<div class="w-8">
<code-icon size="14" />
</div>
<span class="text-sm font-bold">
{{ $t('sharelink.copy_embed') }}
</span>
</li>
</ul>
<!--Hidden options-->
<ul v-if="isOpenedMoreOptions" class="absolute top-12 left-0 right-0 z-10 select-none overflow-y-auto overflow-x-hidden rounded-lg shadow-xl">
<li
@click="getQrCode"
class="block flex cursor-pointer items-center bg-white py-2.5 px-5 hover:bg-light-background dark:bg-2x-dark-foreground dark:hover:bg-4x-dark-foreground"
>
<div class="w-8">
<camera-icon size="14" />
</div>
<span class="text-sm font-bold">
{{ $t('Get QR Code') }}
</span>
</li>
<li
@click="sendViaEmail"
class="block flex cursor-pointer items-center bg-white py-2.5 px-5 hover:bg-light-background dark:bg-2x-dark-foreground dark:hover:bg-4x-dark-foreground"
>
<div class="w-8">
<send-icon size="14" />
</div>
<span class="text-sm font-bold">
{{ $t('sharelink.share_via_email') }}
</span>
</li>
<li
@click="copyIframe"
class="block flex cursor-pointer items-center bg-white py-2.5 px-5 hover:bg-light-background dark:bg-2x-dark-foreground dark:hover:bg-4x-dark-foreground"
>
<div class="w-8">
<code-icon size="14" />
</div>
<span class="text-sm font-bold">
{{ $t('sharelink.copy_embed') }}
</span>
</li>
</ul>
<textarea v-model="iframeCode" ref="iframe" class="absolute right-full opacity-0 pointer-events-none"></textarea>
<textarea v-model="iframeCode" ref="iframe" class="pointer-events-none absolute right-full opacity-0"></textarea>
</div>
</template>
@@ -51,67 +67,64 @@ import { events } from '../../../bus'
export default {
name: 'CopyShareLink',
props: [
'item',
],
props: ['item'],
components: {
MoreHorizontalIcon,
CameraIcon,
MoreHorizontalIcon,
CameraIcon,
CheckIcon,
CopyIcon,
CodeIcon,
SendIcon
CopyIcon,
CodeIcon,
SendIcon,
},
data() {
return {
id: 'link-input-' + Math.floor(Math.random() * 10000000),
iframeCode: '',
id: 'link-input-' + Math.floor(Math.random() * 10000000),
iframeCode: '',
isCopiedLink: false,
isOpenedMoreOptions: false,
isOpenedMoreOptions: false,
}
},
methods: {
moreOptions() {
this.isOpenedMoreOptions = ! this.isOpenedMoreOptions
this.isOpenedMoreOptions = !this.isOpenedMoreOptions
},
getQrCode() {
events.$emit('popup:open', {
name: 'share-edit',
item: this.item,
section: 'qr-code',
})
getQrCode() {
events.$emit('popup:open', {
name: 'share-edit',
item: this.item,
section: 'qr-code',
})
this.isOpenedMoreOptions = false
},
sendViaEmail() {
this.isOpenedMoreOptions = false
},
sendViaEmail() {
events.$emit('popup:open', {
name: 'share-edit',
item: this.item,
section: 'email-sharing',
})
this.isOpenedMoreOptions = false
this.isOpenedMoreOptions = false
},
copyIframe() {
// generate iframe
this.iframeCode = `<iframe src="${this.item.data.relationships.shared.link}" width="790" height="400" allowfullscreen frameborder="0"></iframe>`
copyIframe() {
// generate iframe
this.iframeCode = `<iframe src="${this.item.data.relationships.shared.link}" width="790" height="400" allowfullscreen frameborder="0"></iframe>`
let copyText = this.$refs.iframe
let copyText = this.$refs.iframe
copyText.select()
copyText.setSelectionRange(0, 99999)
copyText.select()
copyText.setSelectionRange(0, 99999)
document.execCommand('copy')
document.execCommand('copy')
events.$emit('toaster', {
type: 'success',
message: this.$t('Your web insert code was copied'),
})
events.$emit('toaster', {
type: 'success',
message: this.$t('Your web insert code was copied'),
})
this.isOpenedMoreOptions = false
this.isOpenedMoreOptions = false
},
copyUrl() {
// Get input value
var copyText = document.getElementById(this.id)
@@ -129,7 +142,7 @@ export default {
setTimeout(() => {
this.isCopiedLink = false
}, 1000)
}
}
},
},
}
</script>

View File

@@ -1,60 +1,58 @@
<template>
<div class="flex items-center mb-8">
<edit-2-icon v-if="!icon" size="22" class="mr-3 vue-feather text-theme dark-text-theme" />
<frown-icon v-if="icon === 'frown'" size="22" class="mr-3 vue-feather text-theme dark-text-theme" />
<file-text-icon v-if="icon === 'file-text'" size="22" class="mr-3 vue-feather text-theme dark-text-theme" />
<dollar-sign-icon v-if="icon === 'dollar'" size="22" class="mr-3 vue-feather text-theme dark-text-theme" />
<credit-card-icon v-if="icon === 'credit-card'" size="22" class="mr-3 vue-feather text-theme dark-text-theme" />
<bar-chart-icon v-if="icon === 'bar-chart'" size="22" class="mr-3 vue-feather text-theme dark-text-theme" />
<settings-icon v-if="icon === 'settings'" size="22" class="mr-3 vue-feather text-theme dark-text-theme" />
<hard-drive-icon v-if="icon === 'hard-drive'" size="22" class="mr-3 vue-feather text-theme dark-text-theme" />
<smartphone-icon v-if="icon === 'smartphone'" size="22" class="mr-3 vue-feather text-theme dark-text-theme" />
<shield-icon v-if="icon === 'shield'" size="22" class="mr-3 vue-feather text-theme dark-text-theme" />
<bell-icon v-if="icon === 'bell'" size="22" class="mr-3 vue-feather text-theme dark-text-theme" />
<key-icon v-if="icon === 'key'" size="22" class="mr-3 vue-feather text-theme dark-text-theme" />
<users-icon v-if="icon === 'users'" size="22" class="mr-3 vue-feather text-theme dark-text-theme" />
<b class="font-bold dark:text-gray-200 sm:text-lg text-md">
<div class="mb-8 flex items-center">
<edit-2-icon v-if="!icon" size="22" class="vue-feather text-theme dark-text-theme mr-3" />
<frown-icon v-if="icon === 'frown'" size="22" class="vue-feather text-theme dark-text-theme mr-3" />
<file-text-icon v-if="icon === 'file-text'" size="22" class="vue-feather text-theme dark-text-theme mr-3" />
<dollar-sign-icon v-if="icon === 'dollar'" size="22" class="vue-feather text-theme dark-text-theme mr-3" />
<credit-card-icon v-if="icon === 'credit-card'" size="22" class="vue-feather text-theme dark-text-theme mr-3" />
<bar-chart-icon v-if="icon === 'bar-chart'" size="22" class="vue-feather text-theme dark-text-theme mr-3" />
<settings-icon v-if="icon === 'settings'" size="22" class="vue-feather text-theme dark-text-theme mr-3" />
<hard-drive-icon v-if="icon === 'hard-drive'" size="22" class="vue-feather text-theme dark-text-theme mr-3" />
<smartphone-icon v-if="icon === 'smartphone'" size="22" class="vue-feather text-theme dark-text-theme mr-3" />
<shield-icon v-if="icon === 'shield'" size="22" class="vue-feather text-theme dark-text-theme mr-3" />
<bell-icon v-if="icon === 'bell'" size="22" class="vue-feather text-theme dark-text-theme mr-3" />
<key-icon v-if="icon === 'key'" size="22" class="vue-feather text-theme dark-text-theme mr-3" />
<users-icon v-if="icon === 'users'" size="22" class="vue-feather text-theme dark-text-theme mr-3" />
<b class="text-md font-bold dark:text-gray-200 sm:text-lg">
<slot></slot>
</b>
</div>
</template>
<script>
import {
UsersIcon,
ShieldIcon,
CreditCardIcon,
DollarSignIcon,
SmartphoneIcon,
HardDriveIcon,
BarChartIcon,
SettingsIcon,
FileTextIcon,
FrownIcon,
Edit2Icon,
BellIcon,
KeyIcon,
} from 'vue-feather-icons'
import {
UsersIcon,
ShieldIcon,
CreditCardIcon,
DollarSignIcon,
SmartphoneIcon,
HardDriveIcon,
BarChartIcon,
SettingsIcon,
FileTextIcon,
FrownIcon,
Edit2Icon,
BellIcon,
KeyIcon,
} from 'vue-feather-icons'
export default {
name: 'FormLabel',
props: [
'icon'
],
components: {
UsersIcon,
CreditCardIcon,
DollarSignIcon,
SmartphoneIcon,
HardDriveIcon,
BarChartIcon,
SettingsIcon,
FileTextIcon,
ShieldIcon,
FrownIcon,
Edit2Icon,
BellIcon,
KeyIcon,
}
}
export default {
name: 'FormLabel',
props: ['icon'],
components: {
UsersIcon,
CreditCardIcon,
DollarSignIcon,
SmartphoneIcon,
HardDriveIcon,
BarChartIcon,
SettingsIcon,
FileTextIcon,
ShieldIcon,
FrownIcon,
Edit2Icon,
BellIcon,
KeyIcon,
},
}
</script>

View File

@@ -4,21 +4,11 @@
<x-icon size="14" class="close-icon text-theme" />
</div>
<input
ref="file"
type="file"
@change="showImagePreview($event)"
class="dummy"
/>
<img
ref="image"
:src="imagePreview"
class="image-preview"
v-if="imagePreview"
/>
<input ref="file" type="file" @change="showImagePreview($event)" class="dummy" />
<img ref="image" :src="imagePreview" class="image-preview" v-if="imagePreview" />
<div class="dropzone-message" v-show="! isData">
<image-icon size="28" class="icon-upload text-theme mx-auto mb-1"/>
<div class="dropzone-message" v-show="!isData">
<image-icon size="28" class="icon-upload text-theme mx-auto mb-1" />
<span class="dropzone-title">
{{ $t('input_image.title') }}
</span>
@@ -30,179 +20,179 @@
</template>
<script>
import { XIcon, ImageIcon } from 'vue-feather-icons'
import { XIcon, ImageIcon } from 'vue-feather-icons'
export default {
name: 'ImageInput',
props: [
'image', 'error'
],
components: {
ImageIcon,
XIcon,
},
data() {
return {
imagePreview: undefined
}
},
computed: {
isData() {
return typeof this.imagePreview === 'undefined' || this.imagePreview === '' ? false : true
},
},
methods: {
resetImage() {
this.imagePreview = undefined
this.$emit('input', undefined)
},
showImagePreview(event) {
const imgPath = event.target.files[0].name,
extn = imgPath
.substring(imgPath.lastIndexOf('.') + 1)
.toLowerCase()
if (['png', 'jpg', 'jpeg', 'svg'].includes(extn)) {
const file = event.target.files[0],
reader = new FileReader()
reader.onload = () => (this.imagePreview = reader.result)
reader.readAsDataURL(file)
// Update user avatar
this.$emit('input', event.target.files[0])
} else {
alert( this.$t('validation_errors.wrong_image') )
}
}
},
created() {
// If has default image then load
if (this.image) this.imagePreview = this.image
export default {
name: 'ImageInput',
props: ['image', 'error'],
components: {
ImageIcon,
XIcon,
},
data() {
return {
imagePreview: undefined,
}
}
},
computed: {
isData() {
return typeof this.imagePreview === 'undefined' || this.imagePreview === '' ? false : true
},
},
methods: {
resetImage() {
this.imagePreview = undefined
this.$emit('input', undefined)
},
showImagePreview(event) {
const imgPath = event.target.files[0].name,
extn = imgPath.substring(imgPath.lastIndexOf('.') + 1).toLowerCase()
if (['png', 'jpg', 'jpeg', 'svg'].includes(extn)) {
const file = event.target.files[0],
reader = new FileReader()
reader.onload = () => (this.imagePreview = reader.result)
reader.readAsDataURL(file)
// Update user avatar
this.$emit('input', event.target.files[0])
} else {
alert(this.$t('validation_errors.wrong_image'))
}
},
},
created() {
// If has default image then load
if (this.image) this.imagePreview = this.image
},
}
</script>
<style lang="scss" scoped>
@import '../../../../sass/vuefilemanager/variables';
@import '../../../../sass/vuefilemanager/mixins';
@import '../../../../sass/vuefilemanager/variables';
@import '../../../../sass/vuefilemanager/mixins';
.dropzone {
border: 1px dashed #a1abc2;
border-radius: 8px;
position: relative;
text-align: center;
display: flex;
align-items: center;
min-height: 175px;
.dropzone {
border: 1px dashed #a1abc2;
border-radius: 8px;
position: relative;
text-align: center;
display: flex;
align-items: center;
min-height: 175px;
&.is-error {
border: 2px dashed rgba(253, 57, 122, 0.3);
&.is-error {
border: 2px dashed rgba(253, 57, 122, 0.3);
.dropzone-title {
color: $danger;
.dropzone-title {
color: $danger;
}
.icon-upload {
rect,
circle,
polyline {
stroke: $danger;
}
}
}
.icon-upload {
rect, circle, polyline {
stroke: $danger
input[type='file'] {
opacity: 0;
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
z-index: 1;
width: 100%;
cursor: pointer;
}
.image-preview {
position: absolute;
width: 100%;
height: 100%;
object-fit: contain;
left: 0;
padding: 25px;
display: block;
&.fit-image {
object-fit: cover;
border-radius: 12px;
overflow: hidden;
}
}
.dropzone-message {
padding: 50px 0;
width: 100%;
.icon-upload {
rect,
circle,
polyline {
color: inherit;
}
}
.dropzone-title {
@include font-size(16);
font-weight: 700;
display: block;
}
.dropzone-description {
color: $text_muted;
@include font-size(12);
}
}
.reset-image {
z-index: 2;
background: white;
border-radius: 50px;
display: block;
position: absolute;
right: 0;
top: 0;
cursor: pointer;
@include transform(translateY(-50%) translateX(50%));
padding: 0px 4px;
box-shadow: 0 1px 5px rgba(0, 0, 0, 0.12);
.close-icon {
vertical-align: middle;
line {
path {
fill: $text;
}
}
}
}
}
input[type='file'] {
opacity: 0;
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
z-index: 1;
width: 100%;
cursor: pointer;
}
.image-preview {
position: absolute;
width: 100%;
height: 100%;
object-fit: contain;
left: 0;
padding: 25px;
display: block;
&.fit-image {
object-fit: cover;
border-radius: 12px;
overflow: hidden;
}
}
.dark {
.dropzone {
border-color: rgba(white, 0.2);
.dropzone-message {
padding: 50px 0;
width: 100%;
.icon-upload {
rect, circle, polyline {
color: inherit
path,
polyline,
line {
color: inherit;
}
}
.dropzone-title {
@include font-size(16);
font-weight: 700;
display: block;
}
.dropzone-description {
color: $text_muted;
@include font-size(12);
}
}
.reset-image {
z-index: 2;
background: white;
border-radius: 50px;
display: block;
position: absolute;
right: 0;
top: 0;
cursor: pointer;
@include transform(translateY(-50%) translateX(50%));
padding: 0px 4px;
box-shadow: 0 1px 5px rgba(0, 0, 0, 0.12);
.close-icon {
vertical-align: middle;
line {
path {
fill: $text;
}
}
}
}
}
.dark {
.dropzone {
border-color: rgba(white, 0.2);
.dropzone-message {
.icon-upload {
path, polyline, line {
color: inherit;
}
}
.dropzone-description {
color: $dark_mode_text_secondary;
}
color: $dark_mode_text_secondary;
}
}
}
}
</style>

View File

@@ -5,27 +5,91 @@
</template>
<script>
export default {
name: 'InfoBox',
props: ['type']
}
export default {
name: 'InfoBox',
props: ['type'],
}
</script>
<style lang="scss" scoped>
@import "../../../../sass/vuefilemanager/variables";
@import '../../../../sass/vuefilemanager/mixins';
@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: 20px;
border-radius: 10px;
margin-bottom: 32px;
background: $light_background;
text-align: left;
padding: 15px;
}
}
.dark {
.info-box {
background: $dark_mode_foreground;
&.error {
background: rgba($danger, 0.1);
p, a {
p,
a {
color: $danger;
}
@@ -35,80 +99,14 @@
}
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;
color: $dark_mode_text_primary;
}
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>

View File

@@ -1,13 +1,22 @@
<template>
<div class="wrapper">
<!--<label class="input-label">{{ label }}:</label>-->
<div class="input-wrapper focus-within-border-theme" :class="{'is-error' : isError}" @click="$refs.input.focus()">
<!--<label class="input-label">{{ label }}:</label>-->
<div class="input-wrapper focus-within-border-theme" :class="{ 'is-error': isError }" @click="$refs.input.focus()">
<div class="email-list">
<div class="email-tag bg-theme-100" :class="{'mb-offset': getCharactersLength > 45}" v-for="(email, i) in emails" :key="i">
<div class="email-tag bg-theme-100" :class="{ 'mb-offset': getCharactersLength > 45 }" v-for="(email, i) in emails" :key="i">
<span class="text-theme">{{ email }}</span>
<x-icon @click="removeEmail(email)" class="icon" size="14"/>
<x-icon @click="removeEmail(email)" class="icon" size="14" />
</div>
<input @keydown.delete=removeLastEmail($event) @keyup="handleEmail()" v-model="email" :size="inputSize" class="email-input" :placeholder="placeHolder" autocomplete="new-password" ref="input"/>
<input
@keydown.delete="removeLastEmail($event)"
@keyup="handleEmail()"
v-model="email"
:size="inputSize"
class="email-input"
:placeholder="placeHolder"
autocomplete="new-password"
ref="input"
/>
</div>
</div>
<span class="error-message" v-if="isError">{{ isError }}</span>
@@ -24,74 +33,68 @@ export default {
props: ['isError', 'label'],
computed: {
getCharactersLength() {
return this.emails.join( '' ).length
return this.emails.join('').length
},
placeHolder() {
return !this.emails.length ? this.$t( 'shared_form.email_placeholder' ) : ''
return !this.emails.length ? this.$t('shared_form.email_placeholder') : ''
},
inputSize() {
return this.email && this.email.length > 14 ? this.email.length : 14
}
},
},
data() {
return {
emails: [],
email: undefined
email: undefined,
}
},
methods: {
removeEmail( email ) {
this.emails = this.emails.filter( item => item !== email )
removeEmail(email) {
this.emails = this.emails.filter((item) => item !== email)
// After romove email send new emails list to parent
events.$emit( 'emailsInputValues', this.emails )
events.$emit('emailsInputValues', this.emails)
},
removeLastEmail( event ) {
removeLastEmail(event) {
// If is input empty and presse backspace remove last email from array
if ( event.code === 'Backspace' && this.email === '' )
this.emails.pop()
if (event.code === 'Backspace' && this.email === '') this.emails.pop()
},
handleEmail() {
if ( this.email.length > 0 ) {
if (this.email.length > 0) {
// Get index of @ and last dot
let lastDot = this.email.lastIndexOf( '.' )
let at = this.email.indexOf( '@' )
let lastDot = this.email.lastIndexOf('.')
let at = this.email.indexOf('@')
// Check if is after @ some dot, if email have @ anf if dont have more like one
if ( lastDot < at || at === -1 || this.email.match(/@/g).length > 1 ) return
if (lastDot < at || at === -1 || this.email.match(/@/g).length > 1) return
// First email dont need to be separated by comma or space to be sended
if( this.emails.length === 0 )
events.$emit('emailsInputValues', [this.email])
if (this.emails.length === 0) events.$emit('emailsInputValues', [this.email])
// After come or backspace push the single email to array or emails
if ( this.email.includes(',') || this.email.includes(' ') ) {
let email = this.email.replace( /[","," "]/, '' )
if (this.email.includes(',') || this.email.includes(' ')) {
let email = this.email.replace(/[","," "]/, '')
this.email = ''
// Push single email to aray of emails
this.emails.push( email )
this.emails.push(email)
events.$emit( 'emailsInputValues', this.emails )
events.$emit('emailsInputValues', this.emails)
}
}
}
},
},
created() {
this.$nextTick(() => {
this.$refs.input.focus()
})
}
},
}
</script>
<style scoped lang="scss">
@import "../../../../sass/vuefilemanager/inapp-forms";
@import '../../../../sass/vuefilemanager/inapp-forms';
@import '../../../../sass/vuefilemanager/forms';
.input-label {
@@ -158,25 +161,24 @@ export default {
.email-input {
width: auto;
border: none ;
border: none;
font-weight: 700;
@include font-size(16);
padding-left: 11px;
&::placeholder {
color: rgba($text-muted, .5)
color: rgba($text-muted, 0.5);
}
}
}
.dark {
.input-wrapper {
background: lighten($dark_mode_foreground, 3%);
background: lighten($dark_mode_foreground, 3%);
.email-list {
.email-input {
background: lighten($dark_mode_foreground, 3%);
background: lighten($dark_mode_foreground, 3%);
color: $dark_mode_text_primary;
&::placeholder {

View File

@@ -6,19 +6,12 @@
<div @click="clearInput" v-if="query" class="icon">
<x-icon class="pointer" size="19"></x-icon>
</div>
<input
v-model="query"
@input="$emit('input', query)"
class="query focus-border-theme"
type="text"
name="searchInput"
:placeholder="$t('search_translations')"
/>
<input v-model="query" @input="$emit('input', query)" class="query focus-border-theme" type="text" name="searchInput" :placeholder="$t('search_translations')" />
</div>
</template>
<script>
import {SearchIcon, XIcon} from 'vue-feather-icons'
import { SearchIcon, XIcon } from 'vue-feather-icons'
export default {
name: 'SearchInput',
@@ -110,5 +103,4 @@ export default {
}
}
}
</style>

View File

@@ -1,92 +1,79 @@
<template>
<div class="select-box">
<div class="box-item active-bg-theme-100 active-border-theme"
:class="{'active': item.value === input}"
@click="getSelectedValue(item)"
v-for="(item, i) in data" :key="i"
>
<div class="box-item active-bg-theme-100 active-border-theme" :class="{ active: item.value === input }" @click="getSelectedValue(item)" v-for="(item, i) in data" :key="i">
<span class="box-value active-text-theme">{{ item.label }}</span>
</div>
</div>
</template>
<script>
export default {
name: 'SelectBoxInput',
props: [
'data',
'value',
],
data() {
return {
input: undefined,
}
},
methods: {
getSelectedValue(item) {
if (! this.input || this.input !== item.value)
this.input = item.value
else
this.input = undefined
this.$emit('input', this.input)
}
},
created() {
if (this.value)
this.input = this.value
export default {
name: 'SelectBoxInput',
props: ['data', 'value'],
data() {
return {
input: undefined,
}
}
},
methods: {
getSelectedValue(item) {
if (!this.input || this.input !== item.value) this.input = item.value
else this.input = undefined
this.$emit('input', this.input)
},
},
created() {
if (this.value) this.input = this.value
},
}
</script>
<style lang="scss" scoped>
@import '../../../../sass/vuefilemanager/variables';
@import '../../../../sass/vuefilemanager/mixins';
@import "../../../../sass/vuefilemanager/inapp-forms";
@import "../../../../sass/vuefilemanager/forms";
@import '../../../../sass/vuefilemanager/variables';
@import '../../../../sass/vuefilemanager/mixins';
@import '../../../../sass/vuefilemanager/inapp-forms';
@import '../../../../sass/vuefilemanager/forms';
.select-box {
display: flex;
justify-content: space-between;
flex-wrap: wrap;
flex-direction: row;
.select-box {
display: flex;
justify-content: space-between;
flex-wrap: wrap;
flex-direction: row;
margin-bottom: 10px;
.box-item {
margin-bottom: 10px;
padding: 12px 4px;
text-align: center;
background: $light_background;
border-radius: 8px;
font-weight: 700;
border: 2px solid $light_background;
cursor: pointer;
flex-direction: column;
flex-basis: 55px;
.box-value {
@include font-size(15);
}
}
}
@media only screen and (max-width: 960px) {
.select-box {
.box-item {
margin-bottom: 10px;
padding: 12px 4px;
text-align: center;
background: $light_background;
border-radius: 8px;
font-weight: 700;
border: 2px solid $light_background;
cursor: pointer;
flex-direction: column;
flex-basis: 55px;
.box-value {
@include font-size(15);
}
flex-basis: calc(34% - 10px);
}
}
}
@media only screen and (max-width: 960px) {
.select-box {
.box-item {
flex-basis: calc(34% - 10px);
}
}
}
.dark {
.select-box {
.box-item {
border-color: $dark_mode_border_color;
background: lighten($dark_mode_foreground, 3%);
}
.dark {
.select-box {
.box-item {
border-color: $dark_mode_border_color;
background: lighten($dark_mode_foreground, 3%);
}
}
}
</style>

View File

@@ -1,22 +1,20 @@
<template>
<div class="select">
<!--Area-->
<div class="input-area bg-light-background rounded-lg" :class="{'is-active': isOpen, 'is-error': isError}" @click="openMenu">
<div class="input-area rounded-lg bg-light-background" :class="{ 'is-active': isOpen, 'is-error': isError }" @click="openMenu">
<!--If is selected-->
<div class="selected w-full flex items-center" v-if="selected">
<div class="selected flex w-full items-center" v-if="selected">
<div class="option-icon" v-if="selected.icon">
<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="whitespace-nowrap w-full inline-block overflow-hidden text-ellipsis option-value pl-2">
{{ selected.label }}
</span>
<span class="option-value inline-block w-full overflow-hidden text-ellipsis whitespace-nowrap pl-2">
{{ selected.label }}
</span>
</div>
<!--If is empty-->
<div class="not-selected" v-if="! selected">
<div class="not-selected" v-if="!selected">
<span class="option-value placehoder">{{ placeholder }}</span>
</div>
@@ -27,7 +25,7 @@
<transition name="slide-in">
<div class="input-options rounded-lg" v-if="isOpen">
<div v-if="options.length > 5" class="select-search">
<input v-model="query" ref="search" type="text" :placeholder="$t('select_search_placeholder')" class="search-input focus-border-theme rounded-lg">
<input v-model="query" ref="search" type="text" :placeholder="$t('select_search_placeholder')" class="search-input focus-border-theme rounded-lg" />
</div>
<ul class="option-list">
<li class="option-item" @click="selectOption(option)" v-for="(option, i) in optionList" :key="i">
@@ -44,126 +42,216 @@
</template>
<script>
import { ChevronDownIcon, Edit2Icon, UserIcon } from 'vue-feather-icons'
import {debounce, omitBy} from "lodash"
import { ChevronDownIcon, Edit2Icon, UserIcon } from 'vue-feather-icons'
import { debounce, omitBy } from 'lodash'
export default {
name:'SelectInput',
props: [
'placeholder',
'options',
'isError',
'default',
],
components: {
Edit2Icon,
UserIcon,
ChevronDownIcon
export default {
name: 'SelectInput',
props: ['placeholder', 'options', 'isError', 'default'],
components: {
Edit2Icon,
UserIcon,
ChevronDownIcon,
},
watch: {
query: debounce(function (val) {
this.searchedResults = omitBy(this.options, (string) => {
return !string.label.toLowerCase().includes(val.toLowerCase())
})
}, 200),
},
computed: {
isSearching() {
return this.searchedResults && this.query !== ''
},
watch: {
query: debounce(function (val) {
this.searchedResults = omitBy(this.options, string => {
return !string.label.toLowerCase().includes(val.toLowerCase())
})
}, 200),
optionList() {
return this.isSearching ? this.searchedResults : this.options
},
computed: {
isSearching() {
return this.searchedResults && this.query !== ''
},
optionList() {
return this.isSearching
? this.searchedResults
: this.options
}
},
data() {
return {
searchedResults: undefined,
selected: undefined,
isOpen: false,
query: '',
}
},
methods: {
selectOption(option) {
// Emit selected
this.$emit('input', option.value)
this.$emit('change', option.value)
// Get selected
this.selected = option
// Close menu
this.isOpen = false
},
openMenu() {
this.isOpen = ! this.isOpen
if (this.isOpen) {
this.$nextTick(() => this.$refs.search.focus());
}
},
},
created() {
if (this.default)
this.selected = this.options.find(option => option.value === this.default)
},
data() {
return {
searchedResults: undefined,
selected: undefined,
isOpen: false,
query: '',
}
}
},
methods: {
selectOption(option) {
// Emit selected
this.$emit('input', option.value)
this.$emit('change', option.value)
// Get selected
this.selected = option
// Close menu
this.isOpen = false
},
openMenu() {
this.isOpen = !this.isOpen
if (this.isOpen) {
this.$nextTick(() => this.$refs.search.focus())
}
},
},
created() {
if (this.default) this.selected = this.options.find((option) => option.value === this.default)
},
}
</script>
<style lang="scss" scoped>
@import '../../../../sass/vuefilemanager/variables';
@import '../../../../sass/vuefilemanager/mixins';
@import '../../../../sass/vuefilemanager/variables';
@import '../../../../sass/vuefilemanager/mixins';
/* TODO: refactor to the tailwind */
/* TODO: refactor to the tailwind */
.select {
position: relative;
user-select: none;
.select {
position: relative;
user-select: none;
width: 100%;
}
.select-search {
background: white;
position: sticky;
top: 0;
padding: 13px;
.search-input {
border: 1px solid transparent;
background: $light_background;
@include transition(150ms);
@include font-size(14);
padding: 13px 20px;
appearance: none;
font-weight: 700;
outline: 0;
width: 100%;
}
}
.input-options {
box-shadow: 0 5px 15px rgba(0, 0, 0, 0.12);
background: white;
position: absolute;
overflow: hidden;
top: 65px;
left: 0;
right: 0;
z-index: 9;
max-height: 295px;
overflow-y: auto;
.option-item {
padding: 13px 20px;
display: block;
cursor: pointer;
&:hover {
color: $theme;
background: $light_background;
}
&:last-child {
border-bottom: none;
}
}
}
.input-area {
border-width: 1px;
border-style: solid;
border-color: transparent;
justify-content: space-between;
@include transition(150ms);
align-items: center;
padding: 13px 20px;
display: flex;
outline: 0;
width: 100%;
cursor: pointer;
.chevron {
@include transition(150ms);
}
&.is-active {
//box-shadow: 0 0 7px rgba($theme, 0.3);
.chevron {
@include transform(rotate(180deg));
}
}
&.is-error {
border-color: $danger;
box-shadow: 0 0 7px rgba($danger, 0.3);
}
}
.option-icon {
width: 20px;
display: inline-block;
@include font-size(10);
}
.option-value {
@include font-size(14);
font-weight: 700;
vertical-align: middle;
&.placehoder {
color: rgba($text, 0.5);
}
}
.slide-in-enter-active {
transition: all 150ms ease;
}
.slide-in-enter /* .list-leave-active below version 2.1.8 */ {
opacity: 0;
transform: translateY(-50px);
}
.dark {
.select-search {
background: white;
position: sticky;
top: 0;
padding: 13px;
background: $dark_mode_foreground;
.search-input {
border: 1px solid transparent;
background: $light_background;
@include transition(150ms);
@include font-size(14);
padding: 13px 20px;
appearance: none;
font-weight: 700;
outline: 0;
width: 100%;
background: $dark_mode_background;
}
}
.input-area {
background: $dark_mode_foreground;
border-color: $dark_mode_foreground;
}
.popup-wrapper {
.input-area {
background: lighten($dark_mode_foreground, 3%);
}
}
.input-options {
box-shadow: 0 5px 15px rgba(0, 0, 0, 0.12);
background: white;
position: absolute;
overflow: hidden;
top: 65px;
left: 0;
right: 0;
z-index: 9;
max-height: 295px;
overflow-y: auto;
background: $dark_mode_foreground;
.option-item {
padding: 13px 20px;
display: block;
cursor: pointer;
border-bottom: none;
&:hover {
color: $theme;
background: $light_background;
background: lighten($dark_mode_foreground, 5%);
.option-icon {
path,
circle {
color: inherit;
}
}
}
&:last-child {
@@ -172,113 +260,10 @@
}
}
.input-area {
border-width: 1px;
border-style: solid;
border-color: transparent;
justify-content: space-between;
@include transition(150ms);
align-items: center;
padding: 13px 20px;
display: flex;
outline: 0;
width: 100%;
cursor: pointer;
.chevron {
@include transition(150ms);
}
&.is-active {
//box-shadow: 0 0 7px rgba($theme, 0.3);
.chevron {
@include transform(rotate(180deg));
}
}
&.is-error {
border-color: $danger;
box-shadow: 0 0 7px rgba($danger, 0.3);
}
}
.option-icon {
width: 20px;
display: inline-block;
@include font-size(10);
}
.option-value {
@include font-size(14);
font-weight: 700;
vertical-align: middle;
&.placehoder {
color: rgba($text, 0.5);
color: $dark_mode_text_secondary;
}
}
.slide-in-enter-active {
transition: all 150ms ease;
}
.slide-in-enter /* .list-leave-active below version 2.1.8 */
{
opacity: 0;
transform: translateY(-50px);
}
.dark {
.select-search {
background: $dark_mode_foreground;
.search-input {
background: $dark_mode_background;
}
}
.input-area {
background: $dark_mode_foreground;
border-color: $dark_mode_foreground;
}
.popup-wrapper {
.input-area {
background: lighten($dark_mode_foreground, 3%);
}
}
.input-options {
background: $dark_mode_foreground;
.option-item {
border-bottom: none;
&:hover {
background: lighten($dark_mode_foreground, 5%);
.option-icon {
path, circle {
color: inherit;
}
}
}
&:last-child {
border-bottom: none;
}
}
}
.option-value {
&.placehoder {
color: $dark_mode_text_secondary;
}
}
}
}
</style>

View File

@@ -7,147 +7,136 @@
</template>
<script>
export default {
name: 'SetupBox',
props: ['title', 'description', 'theme'],
}
export default {
name: 'SetupBox',
props: ['title', 'description', 'theme'],
}
</script>
<style lang="scss" scoped>
@import '../../../../sass/vuefilemanager/variables';
@import '../../../../sass/vuefilemanager/mixins';
@import '../../../../sass/vuefilemanager/variables';
@import '../../../../sass/vuefilemanager/mixins';
.setup-box {
padding: 20px;
border-radius: 8px;
margin-bottom: 30px;
.setup-box {
padding: 20px;
border-radius: 8px;
margin-bottom: 30px;
.title {
@include font-size(21);
margin-bottom: 5px;
display: block;
font-weight: 700;
}
.description {
@include font-size(15);
line-height: 1.5;
margin-bottom: 20px;
}
&.base {
background: $light_background;
}
&.danger {
background: $light_background;
.title {
@include font-size(21);
margin-bottom: 5px;
display: block;
font-weight: 700;
color: $danger;
}
}
/deep/ input {
&[type='text'],
&[type='number'],
.input-area {
background: white;
}
}
/deep/ .input-area {
background: white;
}
/deep/ .form {
margin-top: 20px;
&.block-form {
max-width: 450px;
.single-line-form {
display: flex;
.submit-button {
margin-left: 20px;
}
}
}
}
}
@media only screen and (max-width: 960px) {
.setup-box {
/deep/ .form {
&.block-form {
max-width: 100%;
}
input {
min-width: initial;
}
}
}
}
@media only screen and (max-width: 690px) {
.setup-box {
padding: 15px;
.title {
@include font-size(17);
margin-bottom: 10px;
}
.description {
@include font-size(15);
line-height: 1.5;
margin-bottom: 20px;
@include font-size(14);
}
/deep/ .form.block-form {
.single-line-form {
display: block;
.submit-button {
margin-left: 0;
margin-top: 10px;
}
}
}
}
}
.dark {
.setup-box {
&.base {
background: $light_background;
background: $dark_mode_foreground;
}
&.danger {
background: $light_background;
.title {
color: $danger;
}
background: $dark_mode_foreground;
}
/deep/ input {
&[type='text'],
&[type='number'],
.input-area {
background: white;
background: $dark_mode_background;
}
}
/deep/ .input-area {
background: white;
}
/deep/ .form {
margin-top: 20px;
&.block-form {
max-width: 450px;
.single-line-form {
display: flex;
.submit-button {
margin-left: 20px;
}
}
}
}
}
@media only screen and (max-width: 960px) {
.setup-box {
/deep/ .form {
&.block-form {
max-width: 100%;
}
input {
min-width: initial;
}
}
}
}
@media only screen and (max-width: 690px) {
.setup-box {
padding: 15px;
.title {
@include font-size(17);
margin-bottom: 10px;
}
.description {
@include font-size(14);
}
/deep/ .form.block-form {
.single-line-form {
display: block;
.submit-button {
margin-left: 0;
margin-top: 10px;
}
}
}
}
}
.dark {
.setup-box {
&.base {
background: $dark_mode_foreground;
}
&.danger {
background: $dark_mode_foreground;
}
/deep/ input {
&[type='text'],
&[type='number'],
.input-area {
background: $dark_mode_background;
}
}
/deep/ .input-area {
background: $dark_mode_background;
}
background: $dark_mode_background;
}
}
}
</style>

View File

@@ -1,20 +1,14 @@
<template>
<div class="input-wrapper">
<div class="switch-content">
<label class="input-label" v-if="label">
{{ label }}:
</label>
<label class="input-label" v-if="label"> {{ label }}: </label>
<small class="input-info" v-if="info">
{{ info }}
</small>
{{ info }}
</small>
</div>
<div class="switch-content text-right">
<div
class="switch"
:class="{ active: state }"
@click="changeState"
>
<div class="switch" :class="{ active: state }" @click="changeState">
<div class="switch-button"></div>
</div>
</div>
@@ -22,93 +16,86 @@
</template>
<script>
export default {
name: 'SwitchInput',
props: [
'label',
'name',
'state',
'info',
'input',
],
data() {
return {
isSwitched: undefined
}
},
methods: {
changeState() {
this.isSwitched = !this.isSwitched
this.$emit('input', this.isSwitched)
}
},
mounted() {
this.isSwitched = this.state
}
}
export default {
name: 'SwitchInput',
props: ['label', 'name', 'state', 'info', 'input'],
data() {
return {
isSwitched: undefined,
}
},
methods: {
changeState() {
this.isSwitched = !this.isSwitched
this.$emit('input', this.isSwitched)
},
},
mounted() {
this.isSwitched = this.state
},
}
</script>
<style lang="scss" scoped>
@import '../../../../sass/vuefilemanager/variables';
@import '../../../../sass/vuefilemanager/mixins';
@import '../../../../sass/vuefilemanager/variables';
@import '../../../../sass/vuefilemanager/mixins';
.input-wrapper {
display: flex;
width: 100%;
.input-wrapper {
display: flex;
width: 100%;
.input-label {
color: $text;
}
.input-label {
color: $text;
}
.switch-content {
width: 100%;
.switch-content {
width: 100%;
&:last-child {
width: 80px;
}
}
}
&:last-child {
width: 80px;
}
}
}
.switch {
width: 50px;
height: 28px;
border-radius: 50px;
display: block;
background: #f1f1f5;
position: relative;
@include transition;
.switch {
width: 50px;
height: 28px;
border-radius: 50px;
display: block;
background: #f1f1f5;
position: relative;
@include transition;
.switch-button {
@include transition;
width: 22px;
height: 22px;
border-radius: 50px;
display: block;
background: white;
position: absolute;
top: 3px;
left: 3px;
box-shadow: 0 2px 4px rgba(37, 38, 94, 0.1);
cursor: pointer;
}
.switch-button {
@include transition;
width: 22px;
height: 22px;
border-radius: 50px;
display: block;
background: white;
position: absolute;
top: 3px;
left: 3px;
box-shadow: 0 2px 4px rgba(37, 38, 94, 0.1);
cursor: pointer;
}
&.active {
&.active {
.switch-button {
left: 25px;
}
}
}
.switch-button {
left: 25px;
}
}
}
.dark {
.switch {
background: $dark_mode_foreground;
}
.dark {
.switch {
background: $dark_mode_foreground;
}
.popup-wrapper {
.switch {
background: lighten($dark_mode_foreground, 3%);
}
}
}
.popup-wrapper {
.switch {
background: lighten($dark_mode_foreground, 3%);
}
}
}
</style>