Skip to content

Instantly share code, notes, and snippets.

@iammuttaqi
Last active November 8, 2023 22:14
Show Gist options
  • Save iammuttaqi/b70fd2403a1b038f926847217448fec1 to your computer and use it in GitHub Desktop.
Save iammuttaqi/b70fd2403a1b038f926847217448fec1 to your computer and use it in GitHub Desktop.
TALL stack image cropper using CropperJs (daisy ui as tailwind framework)
<div x-data="data">
<div class="flex w-full flex-col gap-4 md:flex-row">
<label :style="thumbnail ? 'background-image: url(' + thumbnail + ')' : ''" class="tooltip tooltip-bottom grid h-64 w-full cursor-pointer place-items-center rounded border-2 border-dashed border-primary bg-white bg-contain bg-center bg-no-repeat transition-all sm:tooltip-right hover:bg-gray-100 dark:bg-gray-900 dark:hover:bg-gray-800/20 sm:w-64" data-tip="Click to Upload or Replace">
<i class="bi bi-cloud-arrow-up text-8xl text-gray-500 dark:text-gray-400" x-show="!thumbnail"></i>
<input class="hidden" type="file" x-model="image_original" x-on:change="select" />
</label>
<div x-cloak>
<button class="btn btn-warning btn-block mb-4" type="button" x-on:click="modal.showModal()" x-show="image">Crop</button>
<button class="btn btn-error btn-block" type="button" x-on:click="thumbnail = null" x-show="thumbnail">Remove</button>
</div>
</div>
@teleport('body')
<dialog class="modal" id="modal">
<div class="modal-box">
<p>
<img :src="image" class="mw-full block" id="image" wire:ignore>
<div class="modal-action">
<button class="btn btn-primary" x-on:click="crop">Crop</button>
</div>
</p>
</div>
</dialog>
@endteleport
</div>
@push('scripts')
<script>
function data() {
return {
image_original: null,
image: null,
thumbnail: @entangle('thumbnail'),
cropper: null,
select() {
this.image = null;
this.fileToDataUrl(event, src => this.image = src);
this.image_original = null;
let image = document.getElementById('image');
if (this.cropper != null) {
this.cropper.destroy();
}
setTimeout(() => {
this.cropper = new Cropper(image, {
aspectRatio: 1 / 1,
zoomable: false,
dragMode: 'move',
viewMode: 1,
});
}, 500);
if (image) {
modal.showModal()
}
},
crop() {
const self = this;
this.cropper.getCroppedCanvas({
width: 500,
height: 500,
fillColor: '#fff',
imageSmoothingEnabled: false,
imageSmoothingQuality: 'high',
}).toBlob((blob) => {
let reader = new FileReader();
reader.readAsDataURL(blob);
reader.onloadend = function() {
self.thumbnail = reader.result;
modal.close()
}
});
},
fileToDataUrl(event, callback) {
if (!event.target.files.length) return
let file = event.target.files[0],
reader = new FileReader()
reader.readAsDataURL(file)
reader.onload = e => callback(e.target.result)
},
};
}
</script>
@endpush
<?php
namespace App\Http\Livewire\Components;
use Livewire\Attributes\Modelable;
use Livewire\Component;
class ImageCropper extends Component
{
#[Modelable]
public $thumbnail;
public function render()
{
return view('livewire.components.image-cropper');
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment