add ability to update image info

This commit is contained in:
Zutatensuppe 2021-05-22 14:26:04 +02:00
parent 6474c2fd8c
commit 92ed17efa5
12 changed files with 244 additions and 14 deletions

View file

@ -0,0 +1,132 @@
<template>
<div class="overlay edit-image-dialog" @click="$emit('bgclick')">
<div class="overlay-content" @click.stop="">
<div class="area-image">
<div class="has-image">
<responsive-image :src="image.url" :title="image.title" />
</div>
</div>
<div class="area-settings">
<table>
<tr>
<td><label>Title</label></td>
<td><input type="text" v-model="title" placeholder="Flower by @artist" /></td>
</tr>
<tr>
<td colspan="2">
<div class="hint">Feel free to leave a credit to the artist/photographer in the title :)</div>
</td>
</tr>
<tr>
<!-- TODO: autocomplete category -->
<td><label>Category</label></td>
<td><input type="text" v-model="category" placeholder="Plants" /></td>
</tr>
</table>
</div>
<div class="area-buttons">
<button class="btn" @click="saveImage">🖼 Save image</button>
</div>
</div>
</div>
</template>
<script lang="ts">
import { defineComponent, PropType } from 'vue'
import { Image } from '../../common/GameCommon'
import ResponsiveImage from './ResponsiveImage.vue'
export default defineComponent({
name: 'edit-image-dialog',
components: {
ResponsiveImage,
},
props: {
image: {
type: Object as PropType<Image>,
required: true,
},
},
emits: {
bgclick: null,
saveClick: null,
},
data () {
return {
title: '',
category: '',
}
},
created () {
this.title = this.image.title
this.category = this.image.categories.length > 0 ? this.image.categories[0].title : ''
},
methods: {
saveImage () {
this.$emit('saveClick', {
id: this.image.id,
title: this.title,
category: this.category,
})
},
},
})
</script>
// TODO: scoped vs .edit-image-dialog
<style>
.edit-image-dialog .overlay-content {
display: grid;
grid-template-columns: auto 450px;
grid-template-rows: auto;
grid-template-areas:
"image settings"
"image buttons";
height: 90%;
width: 80%;
}
.edit-image-dialog .area-image {
grid-area: image;
margin: 20px;
}
.edit-image-dialog .area-image.no-image {
align-content: center;
display: grid;
text-align: center;
border: dashed 6px;
position: relative;
}
.edit-image-dialog .area-image .has-image {
position: relative;
width: 100%;
height: 100%;
}
.edit-image-dialog .area-image .has-image .remove {
position: absolute;
top: .5em;
left: .5em;
}
.edit-image-dialog .area-settings {
grid-area: settings;
}
.edit-image-dialog .area-settings table input[type="text"] {
width: 100%;
box-sizing: border-box;
}
.edit-image-dialog .area-buttons {
align-self: end;
grid-area: buttons;
}
.edit-image-dialog .area-buttons button {
width: 100%;
margin-top: .5em;
}
</style>

View file

@ -1,6 +1,6 @@
<template>
<div>
<image-teaser v-for="(i,idx) in images" :image="i" @click="imageClicked(i)" :key="idx" />
<image-teaser v-for="(i,idx) in images" :image="i" @click="imageClicked(i)" @editClick="imageEditClicked(i)" :key="idx" />
</div>
</template>
<script lang="ts">
@ -22,11 +22,15 @@ export default defineComponent({
},
emits: {
imageClicked: null,
imageEditClicked: null,
},
methods: {
imageClicked (image: Image) {
this.$emit('imageClicked', image)
},
imageEditClicked (image: Image) {
this.$emit('imageEditClicked', image)
},
},
})
</script>

View file

@ -1,5 +1,10 @@
<template>
<div class="imageteaser" :style="style" @click="onClick"></div>
<div
class="imageteaser"
:style="style"
@click="onClick">
<div class="btn edit" @click.stop="onEditClick"></div>
</div>
</template>
<script lang="ts">
import { defineComponent } from 'vue'
@ -20,10 +25,22 @@ export default defineComponent({
}
},
},
emits: {
click: null,
editClick: null,
},
methods: {
onClick() {
this.$emit('click')
},
onEditClick() {
this.$emit('editClick')
},
},
})
</script>
<style type="css">
.imageteaser { position: relative; }
.imageteaser .edit { display: none; position: absolute; }
.imageteaser:hover .edit { display: inline-block; }
</style>

View file

@ -30,8 +30,9 @@ in jigsawpuzzles.io
</select>
</label>
</div>
<image-library :images="images" @imageClicked="imageClicked" />
<image-library :images="images" @imageClicked="onImageClicked" @imageEditClicked="onImageEditClicked" />
<new-image-dialog v-if="dialog==='new-image'" @bgclick="dialog=''" @postToGalleryClick="postToGalleryClick" @setupGameClick="setupGameClick" />
<edit-image-dialog v-if="dialog==='edit-image'" @bgclick="dialog=''" @saveClick="onSaveImageClick" :image="image" />
<new-game-dialog v-if="image && dialog==='new-game'" @bgclick="dialog=''" @newGame="onNewGame" :image="image" />
</div>
</template>
@ -41,6 +42,7 @@ import { defineComponent } from 'vue'
import ImageLibrary from './../components/ImageLibrary.vue'
import NewImageDialog from './../components/NewImageDialog.vue'
import EditImageDialog from './../components/EditImageDialog.vue'
import NewGameDialog from './../components/NewGameDialog.vue'
import { GameSettings, Image } from '../../common/GameCommon'
import Util from '../../common/Util'
@ -49,6 +51,7 @@ export default defineComponent({
components: {
ImageLibrary,
NewImageDialog,
EditImageDialog,
NewGameDialog,
},
data() {
@ -86,22 +89,46 @@ export default defineComponent({
async filtersChanged () {
await this.loadImages()
},
imageClicked (image: Image) {
onImageClicked (image: Image) {
this.image = image
this.dialog = 'new-game'
},
onImageEditClicked (image: Image) {
this.image = image
this.dialog = 'edit-image'
},
async uploadImage (data: any) {
const formData = new FormData();
formData.append('file', data.file, data.file.name);
formData.append('title', data.title)
formData.append('category', data.category)
const res = await fetch('/upload', {
const res = await fetch('/api/upload', {
method: 'post',
body: formData,
})
return await res.json()
},
async saveImage (data: any) {
const res = await fetch('/api/save-image', {
method: 'post',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
},
body: JSON.stringify({
id: data.id,
title: data.title,
category: data.category,
}),
})
return await res.json()
},
async onSaveImageClick(data: any) {
await this.saveImage(data)
this.dialog = ''
await this.loadImages()
},
async postToGalleryClick(data: any) {
await this.uploadImage(data)
this.dialog = ''