add layers for new image and new game

This commit is contained in:
Zutatensuppe 2021-05-21 00:43:02 +02:00
parent e9b209edf1
commit bdd061dd1a
18 changed files with 551 additions and 99 deletions

View file

@ -0,0 +1,32 @@
<template>
<div>
<image-teaser v-for="(i,idx) in images" :image="i" @click="imageClicked(i)" :key="idx" />
</div>
</template>
<script lang="ts">
import { defineComponent } from 'vue'
import { Image } from '../../common/GameCommon'
import ImageTeaser from './ImageTeaser.vue'
export default defineComponent({
name: 'image-library',
components: {
ImageTeaser,
},
props: {
images: {
type: Array,
required: true,
},
},
emits: {
imageClicked: null,
},
methods: {
imageClicked (image: Image) {
this.$emit('imageClicked', image)
},
},
})
</script>

View file

@ -1,92 +1,86 @@
<template>
<div>
<h1>New game</h1>
<table>
<tr>
<td><label>Pieces: </label></td>
<td><input type="text" v-model="tiles" /></td>
</tr>
<tr>
<td><label>Scoring: </label></td>
<td>
<label><input type="radio" v-model="scoreMode" value="1" /> Any (Score when pieces are connected to each other or on final location)</label>
<br />
<label><input type="radio" v-model="scoreMode" value="0" /> Final (Score when pieces are put to their final location)</label>
</td>
</tr>
<tr>
<td><label>Image: </label></td>
<td>
<span v-if="image">
<img :src="image.url" style="width: 150px;" />
or
<upload @uploaded="mediaImgUploaded($event)" accept="image/*" label="Upload an image" />
</span>
<span v-else>
<upload @uploaded="mediaImgUploaded($event)" accept="image/*" label="Upload an image" />
(or select from below)
</span>
</td>
</tr>
<tr>
<td colspan="2">
<button class="btn" :disabled="!canStartNewGame" @click="onNewGameClick">Start new game</button>
</td>
</tr>
</table>
<div class="overlay new-game-dialog" @click="$emit('bgclick')">
<div class="overlay-content" @click.stop="">
<h1>Image lib</h1>
<div>
<image-teaser v-for="(i,idx) in images" :image="i" @click="image = i" :key="idx" />
<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>Pieces</label></td>
<td><input type="text" v-model="tiles" /></td>
</tr>
<tr>
<td><label>Scoring: </label></td>
<td>
<label><input type="radio" v-model="scoreMode" value="1" /> Any (Score when pieces are connected to each other or on final location)</label>
<br />
<label><input type="radio" v-model="scoreMode" value="0" /> Final (Score when pieces are put to their final location)</label>
</td>
</tr>
</table>
</div>
<div class="area-buttons">
<button class="btn" :disabled="!canStartNewGame" @click="onNewGameClick">
🧩 Generate Puzzle
</button>
</div>
</div>
</div>
</template>
<script lang="ts">
import { defineComponent } from 'vue'
import { ScoreMode } from './../../common/GameCommon'
import Upload from './../components/Upload.vue'
import ImageTeaser from './../components/ImageTeaser.vue'
import { GameSettings, ScoreMode } from './../../common/GameCommon'
import ResponsiveImage from './ResponsiveImage.vue'
export default defineComponent({
name: 'new-game-dialog',
components: {
Upload,
ImageTeaser,
ResponsiveImage,
},
props: {
images: Array,
image: {
type: Object,
required: true,
},
},
emits: {
newGame: null,
bgclick: null,
},
data() {
return {
tiles: 1000,
image: '',
scoreMode: ScoreMode.ANY,
}
},
methods: {
// TODO: ts type UploadedImage
mediaImgUploaded(data: any) {
this.image = data.image
},
canStartNewGame () {
if (!this.tilesInt || !this.image || ![0, 1].includes(this.scoreModeInt)) {
return false
}
return true
},
onNewGameClick() {
onNewGameClick () {
this.$emit('newGame', {
tiles: this.tilesInt,
image: this.image,
scoreMode: this.scoreModeInt,
})
} as GameSettings)
},
},
computed: {
canStartNewGame () {
if (
!this.tilesInt
|| !this.image
|| !this.image.url
|| ![0, 1].includes(this.scoreModeInt)
) {
return false
}
return true
},
scoreModeInt (): number {
return parseInt(`${this.scoreMode}`, 10)
},
@ -96,3 +90,46 @@ export default defineComponent({
},
})
</script>
// TODO: scoped vs .new-game-dialog
<style>
.new-game-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%;
}
.new-game-dialog .area-image {
grid-area: image;
}
.new-game-dialog .area-settings {
grid-area: settings;
}
.new-game-dialog .area-settings table input[type="text"] {
width: 100%;
box-sizing: border-box;
}
.new-game-dialog .area-buttons {
align-self: end;
grid-area: buttons;
}
.new-game-dialog .area-buttons button {
width: 100%;
}
.new-game-dialog .has-image {
position: relative;
width: 100%;
height: 100%;
}
.new-game-dialog .has-image .remove {
position: absolute;
top: .5em;
left: .5em;
}
</style>

View file

@ -0,0 +1,163 @@
"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="">
<div class="area-image" :class="{'has-image': !!image.url, 'no-image': !image.url}">
<!-- TODO: ... -->
<div v-if="image.url" class="has-image">
<span class="remove btn" @click="image.url=''">X</span>
<responsive-image :src="image.url" />
</div>
<div v-else>
<!-- TODO: drop area for image -->
<upload class="upload" @uploaded="mediaImgUploaded($event)" accept="image/*" label="Upload an image" />
</div>
</div>
<div class="area-settings">
<table>
<tr>
<td><label>Title</label></td>
<td><input type="text" v-model="image.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="image.category" placeholder="Plants" /></td>
</tr>
</table>
</div>
<div class="area-buttons">
<!-- <button class="btn" :disabled="!canPostToGallery" @click="postToGallery">🖼 Post to gallery</button> -->
<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'
import Upload from './Upload.vue'
import ResponsiveImage from './ResponsiveImage.vue'
import { Image } from '../../common/GameCommon'
export default defineComponent({
name: 'new-image-dialog',
components: {
Upload,
ResponsiveImage,
},
emits: {
bgclick: null,
setupGameClick: null,
},
data () {
return {
image: {
file: '',
url: '',
title: '',
category: '',
} as Image,
}
},
computed: {
canPostToGallery () {
return !!this.image.url
},
canSetupGameClick () {
return !!this.image.url
},
},
methods: {
mediaImgUploaded(data: any) {
this.image.file = data.image.file
this.image.url = data.image.url
},
postToGallery () {
this.$emit('postToGallery', this.image)
},
setupGameClick () {
this.$emit('setupGameClick', this.image)
},
},
})
</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%;
}
.new-image-dialog .area-image {
grid-area: image;
}
.new-image-dialog .area-image.no-image {
align-content: center;
display: grid;
text-align: center;
margin: 20px;
border: dashed 6px;
position: relative;
}
.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%;
}
.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%);
}
</style>

View file

@ -0,0 +1,37 @@
<template>
<div :style="style" :title="title"></div>
</template>
<script>
export default {
name: 'responsive-image',
props: {
src: String,
title: {
type: String,
default: '',
},
height: {
type: String,
default: '100%',
},
width: {
type: String,
default: '100%',
},
},
computed: {
style() {
return {
display: 'inline-block',
verticalAlign: 'text-bottom',
backgroundImage: `url('${this.src}')`,
backgroundRepeat: 'no-repeat',
backgroundSize: 'contain',
backgroundPosition: 'center',
width: this.width,
height: this.height,
}
},
},
}
</script>