Skip to content

Instantly share code, notes, and snippets.

@eduPHP
Created March 29, 2021 18:17
Show Gist options
  • Select an option

  • Save eduPHP/13267549681c3baef01fe15b16b7fdb1 to your computer and use it in GitHub Desktop.

Select an option

Save eduPHP/13267549681c3baef01fe15b16b7fdb1 to your computer and use it in GitHub Desktop.
<template>
<div role="button" class="flex flex-col justify-center text-center" id="image-div">
<label class="cursor-pointer relative">
<input v-if="!message" type="file" @change="inputImage" class="absolute invisible h-full left-0 top-0 w-full z-20" ref="input" accept="image/*">
<img ref="preview" class="object-cover h-64 w-full" :src="resultImage">
<span class="absolute bottom-0 left-0 mb-4 py-1 text-center text-over text-white w-full z-30">{{trans('dashboard.product-create-image-label')}}</span>
<button v-if="enableDelete" :title="originalImage ? 'Restore Original Image' : 'Remove Image'" @click.prevent="doDelete" class="absolute bg-red-500 m-1 right-0 rounded-full text-white top-0">
<svg class="w-5 h-5 fill-current" viewBox="0 0 1024 1024" xmlns="http://www.w3.org/2000/svg">
<path d="M512.003 64C264.5703 64 64 264.5702 64 511.9918 64 759.4267 264.5702 960 512.003 960 759.4237 960 960 759.4267 960 511.9918 960 264.5702 759.4236 64 512.003 64zm0 836.2662c-214.0951 0-388.2692-174.169-388.2692-388.2754 0-214.085 174.1792-388.261 388.2693-388.261 214.089 0 388.262 174.176 388.262 388.261 0 214.1064-174.173 388.2754-388.262 388.2754zm44.8452-389.2217L695.218 374.1806c12.5725-12.4129 12.6707-32.6727.2537-45.2441-12.418-12.5796-32.7064-12.6768-45.2492-.2599l-138.559 137.0265L375.219 328.8373c-12.5152-12.509-32.7402-12.5776-45.2502-.0625-12.5132 12.4784-12.5439 32.733-.0624 45.2483l136.255 136.6694L328.782 646.5947c-12.5725 12.4528-12.6707 32.6727-.2537 45.2523 6.2704 6.3338 14.4979 9.4992 22.753 9.4992 8.1252 0 16.2555-3.101 22.4952-9.2496L511.3452 556.039l138.686 139.1351c6.2407 6.2704 14.4344 9.403 22.6568 9.403 8.1927 0 16.3517-3.1336 22.5924-9.3396 12.51-12.4804 12.5438-32.7064.0634-45.2492L556.8482 511.0445z"></path>
</svg>
</button>
</label>
<div class="absolute bottom-0 left-0 right-0 top-0 z-50 flex items-center justify-center overlay" v-show="edit || message">
<div v-click-outside="cancel" class="bg-white border modal p-4 rounded shadow">
<div v-if="message">
<alert-inline type="danger">
{{ message }}
</alert-inline>
<div class="mt-4">
<button class="bg-primary-600 border border-gray-400 font-bold px-6 py-1 rounded text-white uppercase" @click="cancel">Ok</button>
</div>
</div>
<div v-show="!message" class="cursor-pointer">
<img ref="image" :src="resultImage" class="cropper-hidden" alt="Image">
</div>
<div v-if="!message" class="mt-4">
<button class="border border-transparent hover:shadow-none hover:underline px-6 py-1" @click="cancel">{{ trans('dashboard.cancel') }}</button>
<button class="bg-primary-600 border border-gray-400 font-bold px-6 py-1 rounded text-white uppercase" @click="getImageData">Ok</button>
</div>
</div>
</div>
</div>
</template>
<script>
import Cropper from 'cropperjs'
import 'cropperjs/src/css/cropper.scss'
import ClickOutside from '../../util/clickOutside'
import { deleteImage } from '../../services/api/checkout'
import AlertInline from '../AlertInline'
export default {
name: 'CheckoutImageCrop',
components: { AlertInline },
props: {
value: {
required: true
},
aspectRatio:{
type: Number,
default: 1,
},
},
directives: { ClickOutside },
data () {
return {
resultImage: '/images/image-placeholder.png',
enableDelete: false,
originalImage: null,
cropper: null,
message: null,
edit: false,
options: {
preview: this.$refs.preview,
aspectRatio: this.aspectRatio,
zoomable: false,
},
}
},
watch: {
value (val) {
this.setup()
},
},
methods: {
deleteImage,
getImageData () {
if(! this.cropper)
return
let croppedCanvas = this.cropper.getCroppedCanvas({
maxWidth: 500,
maxHeight: 500,
});
this.resultImage = croppedCanvas ? croppedCanvas.toDataURL() : this.resultImage
this.$emit('input', this.resultImage)
this.edit = false
this.enableDelete = true
},
cancel () {
this.edit = false
this.message = null
this.$refs.image.value = null
this.setup()
},
doDelete () {
if (typeof this.value !== 'string') {
this.deleteImage(this.value).then(r => {
this.$snotify.info('Imagem removida.')
})
}
this.resultImage = '/images/image-placeholder.png'
this.$emit('input', this.originalImage ? this.originalImage : null)
this.enableDelete = false
this.originalImage = null
},
inputImage (e) {
if (this.value && this.value.url) {
this.originalImage = this.value
}
let image = this.$refs.image
let files = e.target.files
let file
if (files && files.length && (files[0].size / 1024 / 1024) > 1.5) {
this.message = 'Please use an image with 1.5MB or lower size.'
this.edit = true
} else if (files && files.length) {
file = files[0]
if (files && files.length && /^image\/\w+/.test(file.type)) {
image.src = URL.createObjectURL(file)
if (this.cropper) {
this.cropper.destroy()
}
this.cropper = new Cropper(image, this.options)
e.target.value = null
this.edit = true
} else {
this.message = 'Please choose an image file.'
this.edit = true
}
}
},
setup () {
if (this.value && this.value.url) {
this.resultImage = this.value.url
this.enableDelete = true
}
let escapeClose = (e) => {
if (e.key === 'Escape') {
this.cancel()
}
if (e.key === 'Enter' && !this.message) {
this.getImageData()
}
}
document.addEventListener('keydown', escapeClose)
this.$on('hook:beforeDestroy', () => {
document.removeEventListener('keydown', escapeClose)
})
},
},
created() {
this.setup();
}
}
</script>
<style type="text/scss" scoped>
.modal {
max-width: 30rem;
}
.overlay {
background-color: rgba(0, 0, 0, 0.5);
}
.text-over {
background-color: rgba(0, 0, 0, 0.3);
}
#image-div {
max-width: 350px;
min-width: 256px;
}
</style>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment