feat: add ModalDialog

This commit is contained in:
Settel 2022-09-04 20:06:26 +02:00
parent e04dca68bf
commit 3b49ce793f
5 changed files with 217 additions and 27 deletions

View File

@ -101,6 +101,12 @@ $admin-tile-bottom-icon-border: 1px solid #ffffff;
$admin-tile-bottom-icon-hover-background-color: #485058;
$admin-tile-bottom-icon-hover-border: $admin-tile-bottom-icon-border;
// Modal Dialog
$modal-dialog-background-color: #384048;
$modal-dialog-border: none;
$modal-dialog-text-color: #ffffff;
$modal-dialog-backdrop-background-color: rgba(0, 0, 0, 75%);
// Engine Debug
$debug-background-color: lighten($background-primary-color, 10%);
$debug-border: none;

View File

@ -0,0 +1,83 @@
<template>
<div class="modal-dialog__container">
<div class="modal-dialog__box">
<div class="modal-dialog__header">
<div class="modal-dialog__title">{{ title }}</div>
<Button :border="false" @click="emit('close')">x</Button>
</div>
<div class="modal-dialog__body">
<slot />
</div>
<div class="modal-dialog__footer">
<slot name="footer" />
</div>
</div>
<div class="modal-dialog__backdrop" />
</div>
</template>
<script setup lang="ts">
defineProps<{
title?: string
}>()
const emit = defineEmits(['close'])
</script>
<style lang="scss">
@import '~/assets/css/components';
.modal-dialog {
&__container {
display: flex;
position: absolute;
left: 0;
top: 0;
width: 100%;
height: 100%;
}
&__box {
display: flex;
flex-direction: column;
min-width: 400px;
min-height: 280px;
margin: auto;
background-color: $modal-dialog-background-color;
border: $modal-dialog-border;
border-radius: 8px;
color: $modal-dialog-text-color;
z-index: 12;
}
&__header {
display: flex;
}
&__title {
flex-grow: 1;
margin: 16px 16px 8px 16px;
font-family: $font-primary;
font-size: 24px;
}
&__body {
flex-grow: 1;
margin: 16px;
font-family: $font-secondary;
}
&__footer {
display: flex;
justify-content: end;
margin: 24px 16px;
}
&__backdrop {
position: absolute;
width: 100%;
height: 100%;
background-color: $modal-dialog-backdrop-background-color;
z-index: 10;
}
}
</style>

View File

@ -0,0 +1,62 @@
<template>
<ModalDialog v-if="show" :title="title" @close="emit('close')">
<label class="player-dialog__label">Name</label>
<input class="player-dialog__input" v-model="player.name" size="20" />
<label class="player-dialog__label">Score</label>
<input class="player-dialog__input" v-model="player.score" size="20" maxlength="4" />
<label class="player-dialog__label">Authcode</label>
<input class="player-dialog__input" v-model="player.authcode" size="20" maxlength="6" />
<div class="player-dialog__id-container" @click="showId = true">
<span class="player-dialog__id" :class="{ 'player-dialog__id__show': showId }" >{{ player.id }}</span>
</div>
<template v-slot:footer>
<Button @click="emit('submit')">{{ buttonText }}</Button>
</template>
</ModalDialog>
</template>
<script setup lang="ts">
import { ref, watch } from 'vue'
import { PlayerEdit } from '@/composables/engine.d'
const props = defineProps<{
title: string
show: boolean
buttonText: string
player: PlayerEdit
}>()
const emit = defineEmits(['close', 'submit'])
const showId = ref(false)
watch([props], () => { showId.value = false }) // reset visibility each time the dialog is shown
</script>
<style lang="scss">
@import '~/assets/css/components';
.player-dialog {
&__label {
display: block;
margin: 16px 0 4px 0;
}
&__input {
border: 1px solid white;
background-color: $modal-dialog-background-color;
color: $modal-dialog-text-color;
border-radius: 4px;
}
&__id-container {
margin: 16px 0 0 0;
}
&__id {
visibility: hidden;
&__show {
visibility: visible;
}
}
}
</style>

View File

@ -1,30 +1,42 @@
<template>
<AdminTile title="Players" icon-bottom="add" @icon-click="addPlayer">
<table class="players-tile__table">
<tr>
<th class="players-tile__table-head">{{ $t('name') }}:</th>
<th class="players-tile__table-head">{{ $t('num-quotes') }}</th>
<th class="players-tile__table-head">{{ $t('score') }}</th>
<th class="players-tile__table-head">{{ $t('last-logged-in') }}</th>
</tr>
<tr v-for="player in players" class="players-tile__row" :key="player.id">
<td>
{{ player.name }}
<div v-if="player.role === 'gamemaster'" class="players-tile__is-gamemaster"><Icon name="crown" /></div>
</td>
<td>{{ player.numQuotes }}</td>
<td>{{ player.score }}</td>
<td>{{ player.lastLoggedIn === 0 ? '-' : datetime(player.lastLoggedIn) }}</td>
</tr>
</table>
</AdminTile>
<div>
<AdminTile title="Players" icon-bottom="add" @icon-click="addPlayer">
<table class="players-tile__table">
<tr>
<th class="players-tile__table-head">{{ $t('name') }}:</th>
<th class="players-tile__table-head">{{ $t('num-quotes') }}</th>
<th class="players-tile__table-head">{{ $t('score') }}</th>
<th class="players-tile__table-head">{{ $t('last-logged-in') }}</th>
</tr>
<tr v-for="player in players" class="players-tile__row" :key="player.id">
<td>
{{ player.name }}
<div v-if="player.role === 'gamemaster'" class="players-tile__is-gamemaster">
<Icon name="crown" />
</div>
</td>
<td>{{ player.numQuotes }}</td>
<td>{{ player.score }}</td>
<td>{{ player.lastLoggedIn === 0 ? '-' : datetime(player.lastLoggedIn) }}</td>
</tr>
</table>
</AdminTile>
<AdminPlayerDialog
:show="showPlayerDialog"
:title="playerDialogTitle"
:button-text="playerDialogButtonText"
:player="playerDialogPlayer"
@close="showPlayerDialog = false"
@submit="playerDialogSubmit"
/>
</div>
</template>
<script setup lang="ts">
import { computed } from 'vue'
import { computed, ref } from 'vue'
import useI18n from '@/composables/useI18n'
import useDateFormatter from '@/composables/useDateFormatter';
import type { GameInfo } from '@/composables/engine.d'
import type { GameInfo, PlayerEdit } from '@/composables/engine.d'
const props = defineProps<{
gameinfo: GameInfo
@ -43,8 +55,31 @@ const players = computed(() => {
return props.gameinfo.players.sort((a, b) => a.name.localeCompare(b.name))
})
const showPlayerDialog = ref(false)
const playerDialogPlayer = ref({} as PlayerEdit)
const playerDialogTitle = ref('')
const playerDialogButtonText = ref('')
const addPlayer = () => {
alert('not yet implemented')
showPlayerDialog.value = true
playerDialogTitle.value = 'Add new player'
playerDialogButtonText.value = 'Create Player'
playerDialogPlayer.value = {
id: 'asdfasf',
name: '',
score: 0,
authcode: '',
}
}
const editPlayer = (player: PlayerEdit) => {
showPlayerDialog.value = true
playerDialogTitle.value = 'Add new player'
playerDialogButtonText.value = 'Create Player'
playerDialogPlayer.value = player
}
const playerDialogSubmit = () => {
showPlayerDialog.value = false
console.log(playerDialogPlayer.value)
}
</script>

View File

@ -3,11 +3,17 @@ export type Role = 'player' | 'gamemaster' | 'admin'
export type Player = {
id: string
name: string
isIdle: boolean
isIdle?: boolean
score: number
}
export type PlayerInfo = Player & {
export type Players = Array<Player>
export type PlayerEdit = Player & {
authcode?: string
}
export type PlayerInfo = PlayerEdit & {
created: number
lastLoggedIn: number
isPlaying: boolean
@ -15,8 +21,6 @@ export type PlayerInfo = Player & {
role: Role
}
export type Players = Array<Player>
export type Quote = {
id: string
quote: string