Skip to content

Commit 2b5fe00

Browse files
authored
Merge pull request #1 from CraftLogan/add-croppie
Add croppie
2 parents 64ecafc + 270bc5e commit 2b5fe00

File tree

12 files changed

+263
-33
lines changed

12 files changed

+263
-33
lines changed

package.json

+3
Original file line numberDiff line numberDiff line change
@@ -24,5 +24,8 @@
2424
"vue-router": "^3.0.1",
2525
"vue-template-compiler": "^2.5.21",
2626
"vue-textarea-autosize": "^1.0.4"
27+
},
28+
"dependencies": {
29+
"vue-croppie": "^1.3.13"
2730
}
2831
}

public/app.js

+1-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

public/dark.css

+1-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

public/light.css

+1-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

public/mix-manifest.json

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
2-
"/app.js": "/app.js?id=a1763873e1bd0b22663f",
3-
"/light.css": "/light.css?id=00726a847dc6b2cb132a",
4-
"/dark.css": "/dark.css?id=aa5f40a240d2b1df06e2",
2+
"/app.js": "/app.js?id=046923f5b38e64fc7dd8",
3+
"/light.css": "/light.css?id=d21f3947f53c6df3990a",
4+
"/dark.css": "/dark.css?id=2a6bef4dae7be9601f06",
55
"/favicon.png": "/favicon.png?id=b0b34b4095fcdbb8942d"
66
}

resources/js/app.js

+4
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,12 @@ import {Bus} from './bus.js';
44
import Routes from './routes';
55
import VueRouter from 'vue-router';
66
import VueTextareaAutosize from 'vue-textarea-autosize';
7+
import VueCroppie from 'vue-croppie';
8+
79

810
Vue.use(VueRouter);
911
Vue.use(VueTextareaAutosize);
12+
Vue.use(VueCroppie);
1013

1114
const router = new VueRouter({
1215
routes: Routes,
@@ -26,6 +29,7 @@ Vue.component('mini-editor', require('./components/MiniEditor').default);
2629
Vue.component('editor', require('./components/Editor').default);
2730
Vue.component('form-errors', require('./components/FormErrors').default);
2831
Vue.component('image-picker', require('./components/ImagePicker').default);
32+
Vue.component('croppie-modal', require('./components/CroppieModal').default);
2933
Vue.component('date-time-picker', require('./components/DateTimePicker').default);
3034
Vue.component('multiselect', require('./components/MultiSelect').default);
3135
Vue.directive('loading', require('./components/loadingButton'));
+132
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,132 @@
1+
<script type="text/ecmascript-6">
2+
import _ from 'lodash';
3+
4+
export default {
5+
props: ['file','viewport', 'boundary'],
6+
7+
8+
data() {
9+
return {
10+
image: null,
11+
cropped: null,
12+
uploadProgress: 0,
13+
uploading: false
14+
}
15+
},
16+
17+
18+
mounted() {
19+
20+
this.image = this.file;
21+
this.readFile(this.file);
22+
23+
},
24+
25+
26+
methods: {
27+
/**
28+
* This method will close() the modal.
29+
*/
30+
close() {
31+
this.$emit('cancelCroppie');
32+
},
33+
/**
34+
* This method closes croppie and sends the
35+
* cropped image back in the event
36+
*/
37+
closeCroppie() {
38+
this.$emit('closeCroppie', {
39+
avatar: this.avatar
40+
});
41+
},
42+
43+
/**
44+
* This method emits a cancel event.
45+
*/
46+
cancelCroppie() {
47+
this.$emit('cancelCroppie');
48+
},
49+
50+
/**
51+
* This method is used to crop the image
52+
*/
53+
crop() {
54+
// Here we are getting the result via callback function
55+
// and set the result to this.cropped which is being
56+
// used to display the result above.
57+
let options = {
58+
format: 'png',
59+
quality: 1
60+
}
61+
this.$refs.croppieRef.result(options, (output) => {
62+
this.cropped = output;
63+
this.uploadSelectedImage(output);
64+
});
65+
},
66+
67+
68+
/**
69+
* Read File with FileReader Class. So that croppie
70+
* can be binded to the file.
71+
*/
72+
73+
readFile(file) {
74+
75+
let reader = new FileReader();
76+
77+
reader.onload = (e) => {
78+
this.$refs.croppieRef.bind({
79+
url: e.target.result,
80+
zoom: 0
81+
});
82+
}
83+
reader.readAsDataURL(file);
84+
85+
},
86+
87+
/**
88+
* Upload the selected image.
89+
*/
90+
uploadSelectedImage(base64) {
91+
let formData = new FormData();
92+
93+
fetch(base64)
94+
.then(res => res.blob())
95+
.then(blob => {
96+
let file = new File([blob], "filename.jpeg");
97+
formData.append('image', file, file.name);
98+
this.uploading = true;
99+
this.http().post('/api/uploads', formData, {
100+
onUploadProgress: progressEvent => {
101+
this.uploadProgress = Math.round((progressEvent.loaded * 100) / progressEvent.total);
102+
}
103+
}).then(response => {
104+
this.avatar = response.data.url;
105+
this.uploading = false;
106+
this.closeCroppie();
107+
}).catch(error => {
108+
});
109+
});
110+
}
111+
}
112+
}
113+
</script>
114+
115+
<template>
116+
<modal @close="close">
117+
<div :style="{'height':viewport}">
118+
<vue-croppie
119+
ref="croppieRef"
120+
:enableOrientation="true"
121+
:viewport ="viewport"
122+
:boundary="boundary"
123+
:enableResize="true">
124+
</vue-croppie>
125+
</div>
126+
127+
<div class="mt-10">
128+
<button class="btn-sm ml-1 btn-light" @click="cancelCroppie()">Cancel</button>
129+
<button class="btn-sm btn-primary float-right" @click="crop()">Crop Image</button>
130+
</div>
131+
</modal>
132+
</template>

resources/js/components/FullscreenModal.vue

+1-1
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,6 @@
2020

2121
<template>
2222
<transition name="modal">
23-
<slot/>
23+
<slot/>
2424
</transition>
2525
</template>

resources/js/components/ImagePicker.vue

+40-3
Original file line numberDiff line numberDiff line change
@@ -7,15 +7,15 @@
77
88
data() {
99
return {
10+
file: null,
1011
imageUrl: '',
1112
uploadProgress: 100,
12-
1313
selectedUnsplashImage: null,
14-
1514
unsplashSearchTerm: '',
1615
unsplashPage: 1,
1716
searchingUnsplash: false,
1817
unsplashImages: [],
18+
croppieModalShown: false,
1919
}
2020
},
2121
@@ -67,6 +67,14 @@
6767
},
6868
6969
70+
/**
71+
* Load the selected image into Croppie.
72+
*/
73+
loadSelectedImage(event){
74+
this.file = event.target.files[0];
75+
this.croppieModal();
76+
},
77+
7078
/**
7179
* Upload the selected image.
7280
*/
@@ -121,14 +129,37 @@
121129
closeUnsplashModal() {
122130
this.unsplashSearchTerm = '';
123131
this.selectedUnsplashImage = null;
132+
},
133+
134+
/**
135+
* Open Croppie modal.
136+
*/
137+
croppieModal() {
138+
this.croppieModalShown = true;
139+
},
140+
141+
/**
142+
* Close the Croppie modal.
143+
*/
144+
closeCroppieModal({avatar}) {
145+
this.croppieModalShown = false;
146+
this.imageUrl = avatar;
147+
this.$emit('changed', {url: avatar});
148+
},
149+
150+
/**
151+
* Close and Cancel the Croppie modal.
152+
*/
153+
cancelCroppieModal() {
154+
this.croppieModalShown = false;
124155
}
125156
}
126157
}
127158
</script>
128159

129160
<template>
130161
<div>
131-
<input type="file" class="hidden" :id="'imageUpload'+_uid" accept="image/*" v-on:change="uploadSelectedImage">
162+
<input type="file" class="hidden" :id="'imageUpload'+_uid" accept="image/*" v-on:change="loadSelectedImage">
132163

133164
<div class="mb-0">
134165
Please <label :for="'imageUpload'+_uid" class="cursor-pointer underline">upload</label> an image
@@ -167,5 +198,11 @@
167198
</div>
168199
</div>
169200
</fullscreen-modal>
201+
<croppie-modal v-if="croppieModalShown"
202+
:file="file"
203+
:viewport ="{ width: 600, height: 400 }"
204+
:boundary="{ width: 600, height: 400 }"
205+
@closeCroppie="closeCroppieModal"
206+
@cancelCroppie="cancelCroppieModal"></croppie-modal>
170207
</div>
171208
</template>

0 commit comments

Comments
 (0)