feat: add ModalDialog
This commit is contained in:
parent
e04dca68bf
commit
3b49ce793f
@ -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-background-color: #485058;
|
||||||
$admin-tile-bottom-icon-hover-border: $admin-tile-bottom-icon-border;
|
$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
|
// Engine Debug
|
||||||
$debug-background-color: lighten($background-primary-color, 10%);
|
$debug-background-color: lighten($background-primary-color, 10%);
|
||||||
$debug-border: none;
|
$debug-border: none;
|
||||||
|
83
client/src/components/ModalDialog.vue
Normal file
83
client/src/components/ModalDialog.vue
Normal 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>
|
62
client/src/components/admin/PlayerDialog.vue
Normal file
62
client/src/components/admin/PlayerDialog.vue
Normal 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>
|
@ -1,30 +1,42 @@
|
|||||||
<template>
|
<template>
|
||||||
<AdminTile title="Players" icon-bottom="add" @icon-click="addPlayer">
|
<div>
|
||||||
<table class="players-tile__table">
|
<AdminTile title="Players" icon-bottom="add" @icon-click="addPlayer">
|
||||||
<tr>
|
<table class="players-tile__table">
|
||||||
<th class="players-tile__table-head">{{ $t('name') }}:</th>
|
<tr>
|
||||||
<th class="players-tile__table-head">{{ $t('num-quotes') }}</th>
|
<th class="players-tile__table-head">{{ $t('name') }}:</th>
|
||||||
<th class="players-tile__table-head">{{ $t('score') }}</th>
|
<th class="players-tile__table-head">{{ $t('num-quotes') }}</th>
|
||||||
<th class="players-tile__table-head">{{ $t('last-logged-in') }}</th>
|
<th class="players-tile__table-head">{{ $t('score') }}</th>
|
||||||
</tr>
|
<th class="players-tile__table-head">{{ $t('last-logged-in') }}</th>
|
||||||
<tr v-for="player in players" class="players-tile__row" :key="player.id">
|
</tr>
|
||||||
<td>
|
<tr v-for="player in players" class="players-tile__row" :key="player.id">
|
||||||
{{ player.name }}
|
<td>
|
||||||
<div v-if="player.role === 'gamemaster'" class="players-tile__is-gamemaster"><Icon name="crown" /></div>
|
{{ player.name }}
|
||||||
</td>
|
<div v-if="player.role === 'gamemaster'" class="players-tile__is-gamemaster">
|
||||||
<td>{{ player.numQuotes }}</td>
|
<Icon name="crown" />
|
||||||
<td>{{ player.score }}</td>
|
</div>
|
||||||
<td>{{ player.lastLoggedIn === 0 ? '-' : datetime(player.lastLoggedIn) }}</td>
|
</td>
|
||||||
</tr>
|
<td>{{ player.numQuotes }}</td>
|
||||||
</table>
|
<td>{{ player.score }}</td>
|
||||||
</AdminTile>
|
<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>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { computed } from 'vue'
|
import { computed, ref } from 'vue'
|
||||||
import useI18n from '@/composables/useI18n'
|
import useI18n from '@/composables/useI18n'
|
||||||
import useDateFormatter from '@/composables/useDateFormatter';
|
import useDateFormatter from '@/composables/useDateFormatter';
|
||||||
import type { GameInfo } from '@/composables/engine.d'
|
import type { GameInfo, PlayerEdit } from '@/composables/engine.d'
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
gameinfo: GameInfo
|
gameinfo: GameInfo
|
||||||
@ -43,8 +55,31 @@ const players = computed(() => {
|
|||||||
return props.gameinfo.players.sort((a, b) => a.name.localeCompare(b.name))
|
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 = () => {
|
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>
|
</script>
|
||||||
|
|
||||||
|
14
client/src/composables/engine.d.ts
vendored
14
client/src/composables/engine.d.ts
vendored
@ -3,19 +3,23 @@ export type Role = 'player' | 'gamemaster' | 'admin'
|
|||||||
export type Player = {
|
export type Player = {
|
||||||
id: string
|
id: string
|
||||||
name: string
|
name: string
|
||||||
isIdle: boolean
|
isIdle?: boolean
|
||||||
score: number
|
score: number
|
||||||
}
|
}
|
||||||
|
|
||||||
export type PlayerInfo = Player & {
|
export type Players = Array<Player>
|
||||||
|
|
||||||
|
export type PlayerEdit = Player & {
|
||||||
|
authcode?: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export type PlayerInfo = PlayerEdit & {
|
||||||
created: number
|
created: number
|
||||||
lastLoggedIn: number
|
lastLoggedIn: number
|
||||||
isPlaying: boolean
|
isPlaying: boolean
|
||||||
numQuotes: number
|
numQuotes: number
|
||||||
role: Role
|
role: Role
|
||||||
}
|
}
|
||||||
|
|
||||||
export type Players = Array<Player>
|
|
||||||
|
|
||||||
export type Quote = {
|
export type Quote = {
|
||||||
id: string
|
id: string
|
||||||
|
Loading…
Reference in New Issue
Block a user