Created
August 29, 2021 07:17
-
-
Save acidjazz/ae48c2bd5f9ac60ee677d11b3564b141 to your computer and use it in GitHub Desktop.
image upload
This file contains hidden or 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="w-64 h-52 flex justify-center items-center border-2 border-gray-300 border-dashed rounded-md"> | |
<div class="space-y-1 text-center"> | |
<icon-images class="mx-auto w-12 h-12" /> | |
<div class="flex text-sm text-gray-600"> | |
<label for="file-upload" class="relative cursor-pointer bg-white rounded-md font-medium text-fuchsia-600 hover:text-indigo-500 focus-within:outline-none focus-within:ring-2 focus-within:ring-offset-2 focus-within:ring-indigo-500"> | |
<span>Upload an image</span> | |
<input | |
id="file-upload" | |
name="file-upload" | |
type="file" | |
class="sr-only" | |
accept="image/png, image/jpeg, image/gif" | |
@change="change" | |
> | |
</label> | |
<p class="pl-1">or drag and drop</p> | |
</div> | |
<p class="text-xs text-gray-500"> | |
PNG, JPG, GIF up to 10MB | |
</p> | |
<progress-indicator | |
v-for="file in files" | |
:key="file.name" | |
:indeterminate="file.progress === 100" | |
:progress="file.progress" | |
/> | |
</div> | |
</div> | |
</template> | |
<script lang="ts"> | |
import Vue from 'vue' | |
import { PropType } from '@nuxtjs/composition-api' | |
import ProgressIndicator from '@/components/form/ProgressIndicator.vue' | |
export interface UploadFile extends File { | |
// Upload completion progress | |
progress: Number, | |
// Mark complete when axios returns | |
complete: boolean, | |
webkitRelativePath?: string | |
} | |
export type UploadFiles = Array<UploadFile> | |
export default Vue.extend({ | |
components: { ProgressIndicator }, | |
props: { | |
type: String as PropType<'menu'>, | |
id: String, | |
}, | |
data () { | |
return { | |
files: [] as UploadFiles, | |
uploaded: [] as Array<number>, | |
} | |
}, | |
methods: { | |
async change (event: Event & { target: EventTarget & { files: FileList } }): Promise<void> { | |
this.files = Object.values(event.target.files).filter(f => f.name !== '.DS_Store') as UploadFiles | |
await this.uploadAll() | |
}, | |
async uploadAll (): Promise<void> { | |
for (const [index, file] of this.files.entries()) | |
await this.upload(file, index) | |
}, | |
upload (file: UploadFile, index: number): Promise<void>|undefined { | |
if (file.size === 0) { | |
this.$toast.danger('File has zero bytes') | |
this.cancel() | |
return | |
} | |
const data = new FormData() | |
data.append('file', file) | |
data.append('type', this.type) | |
data.append('id', this.id) | |
const config = { | |
headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, | |
onUploadProgress: (event: ProgressEvent) => this.progress(event, file, index), | |
} | |
this.$axios.post('/image', data, config) | |
.then((result) => { | |
this.$toast.show(result.data.data) | |
this.files.forEach((f, i) => { | |
if (f.name === result.data.data.data.name) { | |
f.complete = true | |
this.$set(this.files, i, f) | |
this.uploaded.push(result.data.data.data.id as number) | |
} | |
}) | |
// if all are marked complete, we are done with the upload | |
if (this.files.filter(f => !f.complete).length === 0) { | |
this.files = [] as UploadFiles | |
this.uploaded = [] | |
this.$emit('complete') | |
} | |
}).catch((error) => { | |
console.log('error', error) | |
}) | |
}, | |
cancel (): void { | |
this.files = [] | |
this.$emit('complete') | |
}, | |
progress (event: ProgressEvent, file: UploadFile, index: number): void { | |
file.progress = Math.round(event.loaded * 100 / event.total) | |
this.$set(this.files, index, file) | |
}, | |
}, | |
}) | |
</script> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment