Created
April 24, 2020 20:25
-
-
Save iErik/d91ab301e26c55f009d0298b4445ba12 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<template> | |
<div class="drop-zone"> | |
<div class="drop-zone__box" @click="$refs['fileInput'].click()"> | |
<p class="drop-zone__text"> | |
Arraste aqui seu arquivo ou clique | |
<span class="drop-zone__textHighlight"> | |
para abrir os documentos | |
</span> | |
para fazer upload do arquivo | |
</p> | |
<input | |
ref="fileInput" | |
type="file" | |
class="drop-zone__input" | |
:accept="extensions" | |
:multiple="multiple" | |
@change.prevent="emitUpload" | |
/> | |
</div> | |
<div v-if="$slots.default" class="drop-zone__slot"> | |
<slot /> | |
</div> | |
</div> | |
</template> | |
<script> | |
export default { | |
name: 'DropZone', | |
props: { | |
extensions: { | |
type: Array, | |
required: true | |
}, | |
multiple: { | |
type: Boolean, | |
default: false | |
} | |
}, | |
methods: { | |
emitUpload() { | |
this.$emit('upload', this.$refs.fileInput) | |
} | |
} | |
} | |
</script> | |
<style lang="scss"> | |
.drop-zone { | |
display: flex; | |
flex-direction: column; | |
border: 1px dashed #cccccc; | |
border-radius: 5px; | |
&:hover { | |
border: 1px dashed var(--color-primary); | |
cursor: pointer; | |
.drop-zone__textHighlight { | |
text-decoration: underline; | |
} | |
} | |
&__box { | |
display: flex; | |
justify-content: center; | |
padding: 30px 0; | |
flex-shrink: 0; | |
width: 100%; | |
} | |
&__text { | |
text-decoration: none !important; | |
color: #999; | |
} | |
&__textHighlight { | |
color: var(--color-primary); | |
} | |
&__input { | |
display: none; | |
} | |
} | |
</style> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<template> | |
<div :class="rootClasses"> | |
<div :class="previewClasses"> | |
<div | |
v-if="previewable" | |
:style="imgStyle" | |
class="file-item__preview__img" | |
/> | |
<f-icon | |
v-else | |
name="file" | |
lib="flux" | |
:size="small ? 'base' : 'xl'" | |
color="gray-700" | |
class="file-item__preview__icn" | |
/> | |
</div> | |
<div class="file-item__title">{{ fileName }}</div> | |
<div class="file-item__actions"> | |
<div class="file-item__actions__delete" @click="emitDelete"> | |
<f-icon size="xs" name="X" lib="flux" color="red-700" /> | |
</div> | |
</div> | |
</div> | |
</template> | |
<script> | |
export default { | |
name: 'FileItem', | |
props: { | |
/** | |
* The file to be processed, can be either a File object, | |
* an URL poiting to the file. | |
*/ | |
file: { | |
type: [String, File], | |
required: true | |
}, | |
/** | |
* Makes the FileItem's appaerance more compact. | |
*/ | |
small: { | |
type: Boolean, | |
default: false | |
} | |
}, | |
data: () => ({ | |
loading: false, | |
fileObj: null | |
}), | |
computed: { | |
rootClasses() { | |
return [ | |
'file-item', | |
{ | |
'file-item--loading': this.loading, | |
'file-item--small': this.small | |
} | |
] | |
}, | |
previewClasses() { | |
return [ | |
'file-item__preview', | |
{ | |
'file-item__preview--small': this.small | |
} | |
] | |
}, | |
imgStyle() { | |
if (!this.previewable || this.loading) return {} | |
return { backgroundImage: `url(${this.filePath})` } | |
}, | |
previewable() { | |
if (this.loading || !this.fileObj.type) return | |
return this.fileObj.type.includes('image') | |
}, | |
filePath() { | |
if (!this.previewable || this.loading) return '' | |
return URL.createObjectURL(this.fileObj) || '' | |
}, | |
fileName() { | |
return this.loading ? '' : this.fileObj.name.replace(/\//g, '') | |
} | |
}, | |
created() { | |
if (typeof this.file === 'string' || this.file instanceof String) | |
return this.fetchFile(this.file) | |
this.fileObj = this.file | |
}, | |
methods: { | |
async fetchFile(fileUrl) { | |
this.loading = true | |
const fileName = fileUrl.substring(fileUrl.lastIndexOf('/')) | |
const fileStream = await fetch(fileUrl, { mode: 'no-cors' }) | |
const fileBlob = await fileStream.blob() | |
this.fileObj = new File([fileBlob], fileName) | |
this.loading = false | |
}, | |
emitDelete() { | |
this.$emit('delete', this.file) | |
} | |
} | |
} | |
</script> | |
<style lang="scss"> | |
.file-item { | |
display: flex; | |
border: 1px solid #cccccc; | |
border-radius: 5px; | |
height: 70px; | |
padding-right: 25px; | |
&--small { | |
height: 40px; | |
padding-right: 7px; | |
} | |
&__preview { | |
display: flex; | |
align-items: center; | |
justify-content: center; | |
width: 55px; | |
height: 55px; | |
margin: 7px; | |
margin-right: 15px; | |
&--small { | |
width: 25px; | |
height: 25px; | |
margin-right: 7px; | |
} | |
&__img { | |
border-radius: 3px; | |
width: 100%; | |
height: 100%; | |
background-size: cover; | |
background-repeat: no-repeat; | |
} | |
} | |
&__title { | |
display: flex; | |
align-items: center; | |
flex-grow: 1; | |
color: #999; | |
font-size: 12px; | |
} | |
&__actions { | |
display: flex; | |
align-items: center; | |
&__delete { | |
padding: 3px; | |
border-radius: 50%; | |
border: 1px solid var(--color-red-700); | |
cursor: pointer; | |
} | |
} | |
} | |
</style> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<template> | |
<div :class="classes"> | |
<file-item | |
v-for="(file, index) in files" | |
:key="`${index}-${file.name || file}`" | |
:file="file" | |
class="file-list__item" | |
small | |
@delete="emitDelete($event, index)" | |
/> | |
</div> | |
</template> | |
<script> | |
import FileItem from './FileItem' | |
export default { | |
name: 'FileList', | |
components: { FileItem }, | |
props: { | |
/** | |
* List of files to display | |
*/ | |
files: { | |
type: Array, | |
default: () => [] | |
} | |
}, | |
computed: { | |
classes() { | |
return [ | |
'file-list', | |
{ | |
'file-list--empty': !(this.files || []).length | |
} | |
] | |
} | |
}, | |
methods: { | |
emitDelete(file, index) { | |
this.$emit('delete', { file, index }) | |
} | |
} | |
} | |
</script> | |
<style lang="scss"> | |
.file-list { | |
&:not(&--empty) { | |
padding: 5px; | |
} | |
&__item:not(:last-child) { | |
margin-bottom: 5px; | |
} | |
} | |
</style> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<template> | |
<div | |
class="file-upload" | |
@drop.prevent.stop | |
@dragover.prevent.stop | |
@dragenter.prevent.stop | |
@dragleave.prevent.stop | |
@input.prevent.stop | |
> | |
<transition name="file-upload--fade"> | |
<drop-zone | |
v-if="!hasFiles || multiple" | |
:multiple="multiple" | |
:extensions="extensions" | |
@upload="handleUpload" | |
> | |
<file-list v-if="multiple" :files="value" v-on="$listeners" /> | |
</drop-zone> | |
</transition> | |
<transition name="file-upload--fade"> | |
<file-item v-if="!multiple && value" :file="value" v-on="$listeners" /> | |
</transition> | |
</div> | |
</template> | |
<script> | |
import DropZone from './fragments/DropZone' | |
import FileList from './fragments/FileList' | |
import FileItem from './fragments/FileItem' | |
export default { | |
name: 'FileUpload', | |
components: { | |
DropZone, | |
FileList, | |
FileItem | |
}, | |
props: { | |
/** | |
* List of files. | |
*/ | |
value: { | |
type: [File, String, Array], | |
required: true | |
}, | |
/** | |
* Allowed file extensions | |
*/ | |
extensions: { | |
type: Array, | |
required: true | |
}, | |
/** | |
* Whether the component should support multiple files or not | |
*/ | |
multiple: { | |
type: Boolean, | |
default: false | |
}, | |
/** | |
* Limits the amount of files that the component should accept | |
* in case it is multipe. | |
*/ | |
fileLimit: { | |
type: [Number, String], | |
default: '' | |
} | |
}, | |
computed: { | |
hasFiles() { | |
if (!Array.isArray(this.value)) return !!this.value | |
return !!( | |
(this.value || []).length && | |
this.value.some(f => f && Object.keys(f).length) | |
) | |
} | |
}, | |
methods: { | |
handleUpload({ files }) { | |
if (this.overLimit(files)) return | |
Array.from(files).forEach(file => this.$emit('upload', file)) | |
}, | |
overLimit(files) { | |
if (!Array.isArray(this.values) || !this.fileLimit) return false | |
if (this.fileLimit && (this.value || []).length >= +this.fileLimit) | |
return true | |
return ( | |
Array.from(files).length + (this.value || []).length >= +this.fileLimit | |
) | |
} | |
} | |
} | |
</script> | |
<style lang="scss"> | |
.file-upload { | |
position: relative; | |
&--fade { | |
&-enter-active, | |
&-leave-active { | |
position: absolute; | |
width: 100%; | |
transition: opacity 200ms; | |
} | |
&-enter, | |
&-leave-to { | |
opacity: 0; | |
} | |
} | |
} | |
</style> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<template> | |
<div class="TestPage"> | |
<div class="TestPage-testBox"> | |
<file-upload | |
class="TestPage-fileUpload" | |
:value="files" | |
:extensions="['.jpg', '.png', '.zip', '.rar', '.dmg']" | |
multiple | |
@upload="updateFiles" | |
/> | |
</div> | |
<div class="TestPage-testBox"> | |
<file-upload | |
class="TestPage-fileUpload" | |
:value="file" | |
:extensions="['.jpg', '.png', '.zip', '.rar', '.dmg']" | |
@upload="updateFile" | |
/> | |
</div> | |
</div> | |
</template> | |
<script> | |
import { FileUpload } from '@/components/molecules' | |
export default { | |
name: 'TestPage', | |
layout: 'internal', | |
components: { | |
FileUpload | |
}, | |
data: () => ({ | |
files: [], | |
file: {} | |
}), | |
methods: { | |
updateFiles(file) { | |
this.files.push(file) | |
}, | |
updateFile(file) { | |
this.file = file | |
} | |
} | |
} | |
</script> | |
<style lang="scss"> | |
.TestPage { | |
&-testBox { | |
} | |
&-fileUpload { | |
} | |
} | |
</style> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment