Skip to content

Instantly share code, notes, and snippets.

@adambouchard
Created July 28, 2020 14:25
Show Gist options
  • Save adambouchard/f2413779d423de98d62df282d927c285 to your computer and use it in GitHub Desktop.
Save adambouchard/f2413779d423de98d62df282d927c285 to your computer and use it in GitHub Desktop.
<template>
<div>
<button
@click="upload()"
class="button"
>
{{ label }}
</button>
<modal
v-if="showUploadModal"
:title="label"
@close="cancel"
>
<div
v-if="!hasImage"
class="img-upload"
>
<image-uploader
:preview="false"
:maxWidth="2048"
:maxHeight="2048"
outputFormat="verbose"
@input="setImage"
>
<label for="fileInput" class="has-text-centered" slot="upload-label">
<p class="icon is-large has-text-info">
<font-awesome-icon icon="camera" />
</p>
<p>Click to Select an Image</p>
</label>
</image-uploader>
</div>
<div
v-if="hasImage"
class="img-cropper"
>
<vue-cropper
ref="cropper"
:src="imageSrc"
:aspect-ratio="2 / 1"
:zoomable="false"
:movable="false"
:auto-crop-area="1"
/>
</div>
<template v-slot:footer>
<nav
v-if="hasImage"
class="level is-mobile"
>
<div class="level-left">
<div class="level-item">
<button
class="button has-text-info"
@click.prevent="rotateImage(-90)"
>
<span class="icon">
<font-awesome-icon icon="undo-alt" />
</span>
</button>
</div>
<div class="level-item">
<button
class="button has-text-info"
@click.prevent="rotateImage(90)"
>
<span class="icon">
<font-awesome-icon icon="redo-alt" />
</span>
</button>
</div>
</div>
<div class="level-right">
<div class="level-item">
<button
class="button is-info"
@click.prevent="uploadImage"
>
Upload
</button>
</div>
</div>
</nav>
</template>
</modal>
</div>
</template>
<script>
import * as axios from 'axios';
import ImageUploader from 'vue-image-upload-resize';
import VueCropper from 'vue-cropperjs';
import 'cropperjs/dist/cropper.css';
import Modal from "@/components/Modal.vue";
import { library } from '@fortawesome/fontawesome-svg-core'
import { faCamera, faUndoAlt, faRedoAlt } from '@fortawesome/free-solid-svg-icons'
import { FontAwesomeIcon } from '@fortawesome/vue-fontawesome'
library.add(faCamera)
library.add(faUndoAlt)
library.add(faRedoAlt)
export default {
components: {
Modal, FontAwesomeIcon, ImageUploader, VueCropper
},
data () {
return {
showUploadModal: false,
hasImage: false,
imageSrc: null,
imageType: null,
imageName: null
}
},
props: {
label: {
type: String,
default: "Change Image"
},
},
methods: {
cancel() {
this.showUploadModal = false
this.hasImage = false
this.imageSrc = null
this.imageType = null
this.imageName = null
},
setImage(data) {
this.hasImage = true
this.imageSrc = data.dataUrl
this.imageType = data.info.type
this.imageName = data.info.name
},
rotateImage(deg) {
this.$refs.cropper.rotate(deg)
},
uploadImage() {
// get the cropped image from Cropper
this.$refs.cropper.getCroppedCanvas({
maxWidth: 1280,
maxHeight: 1280,
imageSmoothingQuality: "high"
}).toBlob((blob) => {
// upload the cropped image to Cloudinary
const cloudName = "localloot"
const cloudinaryUrl = `https://api.cloudinary.com/v1_1/${cloudName}/upload`
const formData = new FormData()
formData.append("upload_preset", "dealImages")
formData.append("file", blob, this.imageName)
axios({
url: cloudinaryUrl,
method: "POST",
data: formData,
})
.then(response => {
// save the uploaded image
const image_url = response.data.secure_url
this.$parent.uploadImg(image_url)
this.cancel()
})
.catch(error => {
console.log(error)
alert("Failed to upload image, please try again.")
this.cancel()
})
}, this.imageType)
},
upload() {
this.showUploadModal = true
}
}
}
</script>
<style>
.img-upload {
text-align: center;
}
#fileInput {
display: none;
}
label[for="fileInput"] .icon {
font-size: 4rem;
}
.modal-card-foot .level {
width: 100%;
}
</style>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment