Skip to content

Commit

Permalink
core: frontend: create and use imagepicker
Browse files Browse the repository at this point in the history
  • Loading branch information
Williangalvani committed Apr 9, 2023
1 parent 8586152 commit ea9efd3
Show file tree
Hide file tree
Showing 2 changed files with 329 additions and 29 deletions.
255 changes: 255 additions & 0 deletions core/frontend/src/components/app/ImagePicker.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,255 @@
<template>
<div id="imgdiv">
<v-img id="main" contain :src="image" @click="openDialog()" />
<v-btn
id="edit-icon"
class="mx-2"
fab
dark
x-small
@click="openDialog"
>
<v-icon>
mdi-pencil
</v-icon>
</v-btn>
<v-dialog v-model="dialog" @dragover.prevent @dragenter.prevent @drop.prevent="onDrop">
<v-card class="pa-2">
<v-card-title>
Pick an Image
</v-card-title>
<v-row v-if="images.length > 0" class="overflow-auto" style="max-height: 500px;" justify="space-around">
<v-col v-for="(image2, index) in images" :key="index" cols="12" sm="3" md="3">
<v-card
:class="{ 'selected-image': selectedIndex === index }"
class="image-card"
@click="selectImage(index)"
>
<v-img :src="`${directory}/${image2}`" contain aspect-ratio="1" />
<v-btn
id="trashcan-icon"
class="mx-2"
fab
dark
x-small
@click.stop="deleteImage(index)"
>
<v-icon>
mdi-trash-can
</v-icon>
</v-btn>
</v-card>
</v-col>
</v-row>
<v-row v-else-if="loading">
<SpinningLogo size="100px" />
</v-row>
<v-row v-else>
<v-alert>
No images found at {{ directory }}. Please upload some images to this directory using the file browser.
</v-alert>
<v-alert v-if="error" color="red lighten-2">
{{ error }}
</v-alert>
</v-row>
<v-row>
<v-col cols="12">
<v-card
class="drop-zone"
@dragover.prevent
@dragenter.prevent
@drop.prevent="onDrop"
>
<v-card-text>
Drag and drop an image file here to upload
</v-card-text>
<input
aria-label="File browser"
id="file-input"
ref="fileInput"
type="file"
accept="image/*"
style="display:none"
@change="onFileInputChange"
/>
<v-btn color="primary" @click="onFilePickerClick">
Click to upload an image or
</v-btn>
</v-card>
</v-col>
</v-row>
<v-alert v-if="uploadError" color="red lighten-2">
{{ uploadError }}
</v-alert>
</v-card>
</v-dialog>
</div>
</template>

<script lang="ts">
import axios from 'axios'
import Vue from 'vue'
import back_axios from '@/utils/api'
import SpinningLogo from '../common/SpinningLogo.vue'
interface FileEntry {
name: string;
type: string;
mtime: string;
}
export default Vue.extend({
name: 'ImagePicker',
components: {
SpinningLogo,
},
props: {
directory: {
type: String,
default: '/userdata/images/',
required: false,
},
image: {
type: String,
default: '/userdata/images/',
required: false,
},
},
data() {
return {
dialog: false,
selectedIndex: null as number | null,
images: [] as string[],
error: null as string | null,
loading: true,
uploadError: null as string | null,
}
},
computed: {
},
mounted() {
this.loadImages()
},
methods: {
selectImage(index: number) {
this.selectedIndex = index
this.$emit('image-selected', `${this.directory}/${this.images[index]}`)
this.dialog = false
},
openDialog() {
this.dialog = true
},
loadImages() {
back_axios({
method: 'get',
url: this.directory,
}).then((response) => {
this.images = response.data.filter(
(string: FileEntry) => string.type === 'file',
).map((file: FileEntry) => file.name)
this.loading = false
}).catch((error) => {
this.error = error
})
},
async deleteImage(index: number) {
try {
await back_axios({
method: 'delete',
url: `upload/${this.directory}/${this.images[index]}`,
})
this.loadImages()
} catch (error) {
console.error('Error deleting file:', error)
}
},
onFileInputChange(event: Event) {
const target = event.target as HTMLInputElement
if (target.files && target.files.length > 0) {
const file = target.files[0]
const fileName = encodeURIComponent(file.name)
this.uploadFile(file, `${this.directory}/${fileName}`)
}
},
onFilePickerClick() {
const input = this.$refs.fileInput as HTMLInputElement
input.click()
},
async uploadFile(file: File, destination_path: string) {
try {
const config = {
headers: {
'Content-Type': file.type,
},
}
await axios.put(`/upload/${destination_path}`, file, config)
console.log('File uploaded successfully.')
this.loadImages()
} catch (error) {
console.error('Error uploading file:', error)
}
},
async onDrop(event: DragEvent) {
if (!event.dataTransfer) return
const { files } = event.dataTransfer
if (files.length === 0) return
const file = files[0]
const fileName = encodeURIComponent(file.name)
await this.uploadFile(file, `${this.directory}/${fileName}`)
},
},
})
</script>
<style scoped>
#main {
display: inline-flex;
height: 50px;
width: 50px;
margin: 0px;
object-fit: contain;
position: relative;
}
#edit-icon {
display: none;
position: absolute;
right: -15px;
bottom: 0;
}
#imgdiv:hover #edit-icon{
display: inline-flex !important;
}
#imgdiv {
position:relative;
}
.drop-zone {
border: 2px dashed #ccc;
border-radius: 4px;
text-align: center;
padding: 20px;
margin: 20px 0;
}
.image-card {
position: relative;
}
#trashcan-icon {
display: none;
position: absolute;
top: -10px;
right: -10px;
}
.image-card:hover #trashcan-icon {
display: inline-flex !important;
}
</style>
Loading

0 comments on commit ea9efd3

Please sign in to comment.