2021-05-21 00:43:02 +02:00
|
|
|
|
"Upload image" clicked: what it looks like when the image was uploaded.
|
|
|
|
|
|
Probably needs a (x) in the upper right corner of the image to allow the
|
|
|
|
|
|
user to remove the image if a wrong one was selected. The image should
|
|
|
|
|
|
be uploaded to the actual gallery only when the user presses "post to
|
|
|
|
|
|
gallery", if possible!
|
|
|
|
|
|
<template>
|
|
|
|
|
|
<div class="overlay new-image-dialog" @click="$emit('bgclick')">
|
|
|
|
|
|
<div class="overlay-content" @click.stop="">
|
|
|
|
|
|
|
2021-06-05 09:54:01 +02:00
|
|
|
|
<div
|
|
|
|
|
|
class="area-image"
|
|
|
|
|
|
:class="{'has-image': !!previewUrl, 'no-image': !previewUrl, droppable: droppable}"
|
|
|
|
|
|
@drop="onDrop"
|
|
|
|
|
|
@dragover="onDragover"
|
|
|
|
|
|
@dragleave="onDragleave">
|
2021-05-21 00:43:02 +02:00
|
|
|
|
<!-- TODO: ... -->
|
2021-06-06 16:12:20 +02:00
|
|
|
|
<div class="drop-target"></div>
|
2021-05-22 01:51:44 +02:00
|
|
|
|
<div v-if="previewUrl" class="has-image">
|
|
|
|
|
|
<span class="remove btn" @click="previewUrl=''">X</span>
|
|
|
|
|
|
<responsive-image :src="previewUrl" />
|
2021-05-21 00:43:02 +02:00
|
|
|
|
</div>
|
|
|
|
|
|
<div v-else>
|
2021-05-22 01:51:44 +02:00
|
|
|
|
<label class="upload">
|
2021-06-05 09:54:01 +02:00
|
|
|
|
<input type="file" style="display: none" @change="onFileSelect" accept="image/*" />
|
2021-05-22 15:48:13 +02:00
|
|
|
|
<span class="btn">Upload File</span>
|
2021-05-22 01:51:44 +02:00
|
|
|
|
</label>
|
2021-05-21 00:43:02 +02:00
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<div class="area-settings">
|
|
|
|
|
|
<table>
|
|
|
|
|
|
<tr>
|
|
|
|
|
|
<td><label>Title</label></td>
|
2021-05-22 01:51:44 +02:00
|
|
|
|
<td><input type="text" v-model="title" placeholder="Flower by @artist" /></td>
|
2021-05-21 00:43:02 +02:00
|
|
|
|
</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>
|
2021-05-22 15:48:13 +02:00
|
|
|
|
<!-- TODO: autocomplete tags -->
|
|
|
|
|
|
<td><label>Tags</label></td>
|
|
|
|
|
|
<td>
|
2021-06-03 23:30:08 +02:00
|
|
|
|
<tags-input v-model="tags" :autocompleteTags="autocompleteTags" />
|
2021-05-22 15:48:13 +02:00
|
|
|
|
</td>
|
2021-05-21 00:43:02 +02:00
|
|
|
|
</tr>
|
|
|
|
|
|
</table>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<div class="area-buttons">
|
2021-05-22 01:51:44 +02:00
|
|
|
|
<button class="btn" :disabled="!canPostToGallery" @click="postToGallery">🖼️ Post to gallery</button>
|
2021-05-21 00:43:02 +02:00
|
|
|
|
<button class="btn" :disabled="!canSetupGameClick" @click="setupGameClick">🧩 Post to gallery <br /> + set up game</button>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</template>
|
|
|
|
|
|
<script lang="ts">
|
|
|
|
|
|
import { defineComponent } from 'vue'
|
2021-06-05 09:54:01 +02:00
|
|
|
|
import { logger } from '../../common/Util'
|
2021-05-21 00:43:02 +02:00
|
|
|
|
|
|
|
|
|
|
import ResponsiveImage from './ResponsiveImage.vue'
|
2021-05-22 15:48:13 +02:00
|
|
|
|
import TagsInput from './TagsInput.vue'
|
2021-05-21 00:43:02 +02:00
|
|
|
|
|
2021-06-05 09:54:01 +02:00
|
|
|
|
const log = logger('NewImageDialog.vue')
|
|
|
|
|
|
|
2021-05-21 00:43:02 +02:00
|
|
|
|
export default defineComponent({
|
|
|
|
|
|
name: 'new-image-dialog',
|
|
|
|
|
|
components: {
|
|
|
|
|
|
ResponsiveImage,
|
2021-05-22 15:48:13 +02:00
|
|
|
|
TagsInput,
|
2021-05-21 00:43:02 +02:00
|
|
|
|
},
|
2021-06-03 23:30:08 +02:00
|
|
|
|
props: {
|
|
|
|
|
|
autocompleteTags: {
|
|
|
|
|
|
type: Function,
|
|
|
|
|
|
},
|
|
|
|
|
|
},
|
2021-05-21 00:43:02 +02:00
|
|
|
|
emits: {
|
|
|
|
|
|
bgclick: null,
|
|
|
|
|
|
setupGameClick: null,
|
2021-05-22 01:51:44 +02:00
|
|
|
|
postToGalleryClick: null,
|
2021-05-21 00:43:02 +02:00
|
|
|
|
},
|
|
|
|
|
|
data () {
|
|
|
|
|
|
return {
|
2021-05-22 01:51:44 +02:00
|
|
|
|
previewUrl: '',
|
|
|
|
|
|
file: null as File|null,
|
|
|
|
|
|
title: '',
|
2021-05-22 15:48:13 +02:00
|
|
|
|
tags: [] as string[],
|
2021-06-05 09:54:01 +02:00
|
|
|
|
droppable: false,
|
2021-05-21 00:43:02 +02:00
|
|
|
|
}
|
|
|
|
|
|
},
|
|
|
|
|
|
computed: {
|
2021-05-22 01:51:44 +02:00
|
|
|
|
canPostToGallery (): boolean {
|
|
|
|
|
|
return !!(this.previewUrl && this.file)
|
2021-05-21 00:43:02 +02:00
|
|
|
|
},
|
2021-05-22 01:51:44 +02:00
|
|
|
|
canSetupGameClick (): boolean {
|
|
|
|
|
|
return !!(this.previewUrl && this.file)
|
2021-05-21 00:43:02 +02:00
|
|
|
|
},
|
|
|
|
|
|
},
|
|
|
|
|
|
methods: {
|
2021-06-05 09:54:01 +02:00
|
|
|
|
imageFromDragEvt (evt: DragEvent): DataTransferItem|null {
|
|
|
|
|
|
const items = evt.dataTransfer?.items
|
|
|
|
|
|
if (!items || items.length === 0) {
|
|
|
|
|
|
return null
|
|
|
|
|
|
}
|
|
|
|
|
|
const item = items[0]
|
|
|
|
|
|
if (!item.type.startsWith('image/')) {
|
|
|
|
|
|
return null
|
|
|
|
|
|
}
|
|
|
|
|
|
return item
|
|
|
|
|
|
},
|
|
|
|
|
|
onFileSelect (evt: Event) {
|
2021-05-22 01:51:44 +02:00
|
|
|
|
const target = (evt.target as HTMLInputElement)
|
|
|
|
|
|
if (!target.files) return;
|
|
|
|
|
|
const file = target.files[0]
|
|
|
|
|
|
if (!file) return;
|
|
|
|
|
|
|
2021-06-05 09:54:01 +02:00
|
|
|
|
this.preview(file)
|
|
|
|
|
|
},
|
|
|
|
|
|
preview (file: File) {
|
2021-05-22 01:51:44 +02:00
|
|
|
|
const r = new FileReader()
|
|
|
|
|
|
r.readAsDataURL(file)
|
|
|
|
|
|
r.onload = (ev: any) => {
|
|
|
|
|
|
this.previewUrl = ev.target.result
|
|
|
|
|
|
this.file = file
|
|
|
|
|
|
}
|
2021-05-21 00:43:02 +02:00
|
|
|
|
},
|
|
|
|
|
|
postToGallery () {
|
2021-05-22 01:51:44 +02:00
|
|
|
|
this.$emit('postToGalleryClick', {
|
|
|
|
|
|
file: this.file,
|
|
|
|
|
|
title: this.title,
|
2021-05-22 15:48:13 +02:00
|
|
|
|
tags: this.tags,
|
2021-05-22 01:51:44 +02:00
|
|
|
|
})
|
2021-05-21 00:43:02 +02:00
|
|
|
|
},
|
|
|
|
|
|
setupGameClick () {
|
2021-05-22 01:51:44 +02:00
|
|
|
|
this.$emit('setupGameClick', {
|
|
|
|
|
|
file: this.file,
|
|
|
|
|
|
title: this.title,
|
2021-05-22 15:48:13 +02:00
|
|
|
|
tags: this.tags,
|
2021-05-22 01:51:44 +02:00
|
|
|
|
})
|
2021-05-21 00:43:02 +02:00
|
|
|
|
},
|
2021-06-05 09:54:01 +02:00
|
|
|
|
onDrop (evt: DragEvent): boolean {
|
|
|
|
|
|
this.droppable = false
|
|
|
|
|
|
const img = this.imageFromDragEvt(evt)
|
|
|
|
|
|
if (!img) {
|
|
|
|
|
|
return false
|
|
|
|
|
|
}
|
|
|
|
|
|
const f = img.getAsFile()
|
|
|
|
|
|
if (!f) {
|
|
|
|
|
|
return false
|
|
|
|
|
|
}
|
|
|
|
|
|
this.file = f
|
|
|
|
|
|
this.preview(f)
|
|
|
|
|
|
evt.preventDefault()
|
|
|
|
|
|
return false
|
|
|
|
|
|
},
|
|
|
|
|
|
onDragover (evt: DragEvent): boolean {
|
|
|
|
|
|
const img = this.imageFromDragEvt(evt)
|
|
|
|
|
|
if (!img) {
|
|
|
|
|
|
return false
|
|
|
|
|
|
}
|
|
|
|
|
|
this.droppable = true
|
|
|
|
|
|
evt.preventDefault()
|
|
|
|
|
|
return false
|
|
|
|
|
|
},
|
|
|
|
|
|
onDragleave () {
|
|
|
|
|
|
log.info('onDragleave')
|
|
|
|
|
|
this.droppable = false
|
|
|
|
|
|
},
|
2021-05-21 00:43:02 +02:00
|
|
|
|
},
|
|
|
|
|
|
})
|
|
|
|
|
|
</script>
|
|
|
|
|
|
|
|
|
|
|
|
// TODO: scoped vs .new-image-dialog
|
|
|
|
|
|
<style>
|
|
|
|
|
|
.new-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%;
|
|
|
|
|
|
}
|
2021-06-05 09:54:01 +02:00
|
|
|
|
@media (max-width: 1400px) {
|
|
|
|
|
|
.new-image-dialog .overlay-content {
|
|
|
|
|
|
grid-template-columns: auto;
|
|
|
|
|
|
grid-template-rows: 1fr min-content min-content;
|
|
|
|
|
|
grid-template-areas:
|
|
|
|
|
|
"image"
|
|
|
|
|
|
"settings"
|
|
|
|
|
|
"buttons";
|
|
|
|
|
|
}
|
2021-06-05 09:59:59 +02:00
|
|
|
|
.new-image-dialog .overlay-content .area-buttons .btn br {
|
|
|
|
|
|
display: none;
|
|
|
|
|
|
}
|
2021-06-05 09:54:01 +02:00
|
|
|
|
}
|
2021-05-21 00:43:02 +02:00
|
|
|
|
|
|
|
|
|
|
.new-image-dialog .area-image {
|
|
|
|
|
|
grid-area: image;
|
2021-06-05 09:59:59 +02:00
|
|
|
|
margin: .5em;
|
|
|
|
|
|
border: solid 6px transparent;
|
2021-05-21 00:43:02 +02:00
|
|
|
|
}
|
|
|
|
|
|
.new-image-dialog .area-image.no-image {
|
|
|
|
|
|
align-content: center;
|
|
|
|
|
|
display: grid;
|
|
|
|
|
|
text-align: center;
|
2021-06-05 09:54:01 +02:00
|
|
|
|
border: solid 6px;
|
2021-05-21 00:43:02 +02:00
|
|
|
|
position: relative;
|
|
|
|
|
|
}
|
2021-06-05 09:54:01 +02:00
|
|
|
|
.new-image-dialog .area-image.droppable {
|
|
|
|
|
|
border: dashed 6px;
|
|
|
|
|
|
}
|
2021-05-21 00:43:02 +02:00
|
|
|
|
.new-image-dialog .area-image .has-image {
|
|
|
|
|
|
position: relative;
|
|
|
|
|
|
width: 100%;
|
|
|
|
|
|
height: 100%;
|
|
|
|
|
|
}
|
|
|
|
|
|
.new-image-dialog .area-image .has-image .remove {
|
|
|
|
|
|
position: absolute;
|
|
|
|
|
|
top: .5em;
|
|
|
|
|
|
left: .5em;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.new-image-dialog .area-settings {
|
|
|
|
|
|
grid-area: settings;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.new-image-dialog .area-settings table input[type="text"] {
|
|
|
|
|
|
width: 100%;
|
|
|
|
|
|
box-sizing: border-box;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.new-image-dialog .area-buttons {
|
|
|
|
|
|
align-self: end;
|
|
|
|
|
|
grid-area: buttons;
|
|
|
|
|
|
}
|
|
|
|
|
|
.new-image-dialog .area-buttons button {
|
|
|
|
|
|
width: 100%;
|
2021-05-22 01:51:44 +02:00
|
|
|
|
margin-top: .5em;
|
2021-05-21 00:43:02 +02:00
|
|
|
|
}
|
|
|
|
|
|
.new-image-dialog .upload {
|
|
|
|
|
|
position: absolute;
|
|
|
|
|
|
top: 0;
|
|
|
|
|
|
left: 0;
|
|
|
|
|
|
right: 0;
|
|
|
|
|
|
bottom: 0;
|
|
|
|
|
|
cursor: pointer;
|
|
|
|
|
|
}
|
|
|
|
|
|
.new-image-dialog .upload .btn {
|
|
|
|
|
|
position: absolute;
|
|
|
|
|
|
top: 50%;
|
|
|
|
|
|
transform: translate(-50%,-50%);
|
|
|
|
|
|
}
|
2021-06-06 16:12:20 +02:00
|
|
|
|
.area-image .drop-target {
|
|
|
|
|
|
display: none;
|
|
|
|
|
|
}
|
|
|
|
|
|
.area-image.droppable .drop-target {
|
|
|
|
|
|
pointer-events: none;
|
|
|
|
|
|
position: absolute;
|
|
|
|
|
|
top: 0;
|
|
|
|
|
|
left: 0;
|
|
|
|
|
|
right: 0;
|
|
|
|
|
|
bottom: 0;
|
|
|
|
|
|
z-index: 3;
|
|
|
|
|
|
}
|
2021-05-21 00:43:02 +02:00
|
|
|
|
</style>
|