Skip to content

Instantly share code, notes, and snippets.

@b4n92uid
Created March 12, 2021 00:13
Show Gist options
  • Save b4n92uid/84ed75bbdd6a2af4bc9b220d08604533 to your computer and use it in GitHub Desktop.
Save b4n92uid/84ed75bbdd6a2af4bc9b220d08604533 to your computer and use it in GitHub Desktop.
[Vuetify] PictureField Base64
<template>
<v-card
class="v-picture-field rounded-lg"
:loading="loading > 0"
outlined
:class="{
'--has-content': value !== null
}"
@click.stop="sourceDialog = true"
>
<input
ref="field"
type="file"
class="__input"
accept="image/*"
@click.stop
@change="onFileSelected"
/>
<div v-if="value">
<div class="py-4 rounded-lg">
<v-img :src="value" :aspect-ratio="16 / 9" contain> </v-img>
</div>
<div class="d-flex justify-space-between">
<v-btn color="primary" text small @click.stop="choose">
<v-icon left small>mdi-camera</v-icon>
Choisir
</v-btn>
<v-btn color="red" text small @click.stop="clear">
<v-icon left small>mdi-delete</v-icon>
Supprimer
</v-btn>
</div>
</div>
<div v-else>
<v-responsive
:aspect-ratio="16 / 9"
class="d-flex justify-center align-center"
>
<div class="text-center pa-4 grey--text">
<v-icon color="grey" size="128">mdi-camera</v-icon>
<div>Sélectionner ou prenez une photo</div>
</div>
</v-responsive>
</div>
<v-bottom-sheet v-model="sourceDialog" inset>
<v-sheet tile>
<v-list>
<v-list-item @click.stop="fromCamera">
<v-list-item-icon>
<v-icon>mdi-camera</v-icon>
</v-list-item-icon>
<v-list-item-title>Prendre une photo</v-list-item-title>
</v-list-item>
<v-list-item @click.stop="fromDevice">
<v-list-item-icon>
<v-icon>mdi-folder-open</v-icon>
</v-list-item-icon>
<v-list-item-title>Choisir depuis l'appareil</v-list-item-title>
</v-list-item>
</v-list>
</v-sheet>
</v-bottom-sheet>
</v-card>
</template>
<script>
import imageCompression from "browser-image-compression";
import { Plugins, CameraResultType, CameraSource } from "@capacitor/core";
export default {
props: {
value: {
type: String,
default: null
}
},
data() {
return {
loading: 0,
sourceDialog: false
};
},
methods: {
isImageSizeValid(src, { width, height }) {
return new Promise(resolve => {
const loader = new Image();
loader.onload = () =>
resolve(loader.width <= width && loader.height <= height);
loader.src = src;
});
},
async readAsDataURL(f) {
return new Promise(resolve => {
const reader = new FileReader();
reader.addEventListener("load", () => resolve(reader.result), false);
reader.readAsDataURL(f);
});
},
async onFileSelected() {
if (!this.$refs.field.files.length) return;
let [file] = this.$refs.field.files;
this.loading++;
file = await imageCompression(file, {
maxSizeMB: 1
});
const dataUri = await this.readAsDataURL(file);
this.$emit("input", dataUri);
this.$refs.field.files.value = "";
this.loading--;
},
async fromCamera() {
this.sourceDialog = false;
const { Camera } = Plugins;
try {
const image = await Camera.getPhoto({
quality: 80,
width: 1024,
resultType: CameraResultType.Uri,
source: CameraSource.Camera
});
this.loading++;
this.$emit("input", image.webPath);
} catch (error) {
// TODO: Handle error
}
this.loading--;
},
fromDevice() {
this.sourceDialog = false;
this.$nextTick(() => this.$refs.field.click());
},
async choose() {
if (process.env.VUE_APP_IS_CAPACITOR) this.sourceDialog = true;
else this.fromDevice();
},
clear() {
this.$refs.field.files.value = "";
this.$emit("input", null);
}
}
};
</script>
<style lang="scss">
.v-picture-field.v-card {
> .__input {
display: none;
}
border: thin dashed rgba(0, 0, 0, 0.12);
&.--has-content {
border: thin solid rgba(0, 0, 0, 0.12);
}
}
</style>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment