Updated tiles, improved folder & file structure, npm update, more progress on zone editor
This commit is contained in:
@ -1,326 +0,0 @@
|
||||
<template>
|
||||
<div class="character-select-screen">
|
||||
<div class="ui-wrapper">
|
||||
<div class="characters-wrapper" v-if="!isLoading">
|
||||
<div v-for="character in characters" :key="character.id" class="character" :class="{ active: selected_character == character.id }">
|
||||
<input type="radio" :id="character.id" name="character" :value="character.id" v-model="selected_character" />
|
||||
<label :for="character.id">{{ character.name }}</label>
|
||||
<!-- @TODO : Add a confirmation dialog -->
|
||||
<button class="delete" @click="delete_character(character.id)">
|
||||
<img draggable="false" src="/assets/icons/trashcan.svg" />
|
||||
</button>
|
||||
|
||||
<div class="sprite-container">
|
||||
<img draggable="false" src="/assets/avatar/default/0.png" />
|
||||
</div>
|
||||
<span>Lvl. {{ character.level }}</span>
|
||||
</div>
|
||||
|
||||
<div class="character new-character" v-if="characters.length < 4">
|
||||
<button @click="isModalOpen = true">
|
||||
<img draggable="false" src="/assets/icons/plus-icon.svg" />
|
||||
<span>Create new</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div v-else>
|
||||
<div class="loading-spinner">
|
||||
<img src="/assets/icons/loading-icon1.svg" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="button-wrapper" v-if="!isLoading">
|
||||
<button class="btn-cyan" :disabled="!selected_character" @click="select_character()">
|
||||
PLAY
|
||||
<img draggable="false" src="/assets/icons/arrow.svg" />
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<Modal :isModalOpen="isModalOpen" @modal:close="isModalOpen = false">
|
||||
<template #modalHeader>
|
||||
<h3 class="modal-title">Create your character</h3>
|
||||
</template>
|
||||
|
||||
<template #modalBody>
|
||||
<form method="post" @submit.prevent="create" class="modal-form">
|
||||
<div class="form-fields">
|
||||
<label for="name">Name</label>
|
||||
<input v-model="name" name="name" id="name" />
|
||||
</div>
|
||||
<div class="submit">
|
||||
<button class="btn-cyan" type="submit">CREATE</button>
|
||||
</div>
|
||||
</form>
|
||||
<button class="btn-cyan" @click="isModalOpen = false">CANCEL</button>
|
||||
</template>
|
||||
</Modal>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { useSocketStore } from '@/stores/socket'
|
||||
import { onBeforeMount, onBeforeUnmount, onMounted, ref } from 'vue'
|
||||
import Modal from '@/components/utilities/Modal.vue'
|
||||
import { type Character as CharacterT } from '@/types'
|
||||
|
||||
const isLoading = ref(true)
|
||||
const characters = ref([])
|
||||
const socket = useSocketStore()
|
||||
|
||||
// Fetch characters
|
||||
socket.connection.on('character:list', (data: any) => {
|
||||
characters.value = data
|
||||
})
|
||||
|
||||
onMounted(() => {
|
||||
// wait 1.5 sec
|
||||
setTimeout(() => {
|
||||
socket.connection.emit('character:list')
|
||||
isLoading.value = false
|
||||
}, 1000)
|
||||
})
|
||||
|
||||
// Select character logics
|
||||
const selected_character = ref(null)
|
||||
function select_character() {
|
||||
if (!selected_character.value) return
|
||||
socket.connection.emit('character:connect', { character_id: selected_character.value })
|
||||
socket.connection.on('character:connect', (data: CharacterT) => socket.setCharacter(data))
|
||||
}
|
||||
|
||||
// Delete character logics
|
||||
function delete_character(character_id: number) {
|
||||
if (!character_id) return
|
||||
socket.connection.emit('character:delete', { character_id: character_id })
|
||||
}
|
||||
|
||||
// Create character logics
|
||||
const isModalOpen = ref(false)
|
||||
const name = ref('')
|
||||
function create() {
|
||||
socket.connection.on('character:create:success', (data: CharacterT) => {
|
||||
socket.setCharacter(data)
|
||||
isModalOpen.value = false
|
||||
})
|
||||
socket.connection.emit('character:create', { name: name.value })
|
||||
}
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
socket.connection.off('character:list')
|
||||
socket.connection.off('character:connect')
|
||||
socket.connection.off('character:create:success')
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
@import '@/assets/scss/main';
|
||||
|
||||
.character-select-screen {
|
||||
&::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
background-image: url('/assets/shapes/select-screen-bg-shape.svg');
|
||||
background-repeat: no-repeat;
|
||||
background-position: center;
|
||||
background-size: 100% cover;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
background-color: $dark-gray;
|
||||
position: relative;
|
||||
|
||||
.ui-wrapper {
|
||||
height: 100vh;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
gap: 80px;
|
||||
padding: 0 80px;
|
||||
&::before {
|
||||
content: '';
|
||||
}
|
||||
|
||||
.loading-spinner img {
|
||||
width: 5rem;
|
||||
// css color
|
||||
filter: invert(1);
|
||||
// white
|
||||
filter: invert(80%);
|
||||
}
|
||||
|
||||
.characters-wrapper {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
flex-wrap: wrap;
|
||||
gap: 60px;
|
||||
width: 100%;
|
||||
max-height: 650px;
|
||||
overflow: auto;
|
||||
|
||||
.character {
|
||||
margin: 15px;
|
||||
width: 170px;
|
||||
height: 275px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
border-radius: 20px;
|
||||
position: relative;
|
||||
background-repeat: no-repeat;
|
||||
background-image: url('/assets/shapes/character-select-shape-2.svg');
|
||||
box-shadow: 0 4px 30px rgba($black, 0.1);
|
||||
|
||||
&::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
max-width: 0;
|
||||
width: 65%;
|
||||
height: 3px;
|
||||
background-color: $white;
|
||||
border-radius: 3px;
|
||||
left: 50%;
|
||||
bottom: -15px;
|
||||
transform: translateX(-50%);
|
||||
transition: ease-in-out max-width 0.3s;
|
||||
}
|
||||
|
||||
&.active::after {
|
||||
max-width: 170px;
|
||||
}
|
||||
|
||||
&.new-character {
|
||||
background-color: rgba($light-gray, 0.5);
|
||||
background-image: none;
|
||||
|
||||
button {
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
padding: 40px 0;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: space-between;
|
||||
&::before {
|
||||
content: '';
|
||||
}
|
||||
img {
|
||||
width: 100px;
|
||||
height: 100px;
|
||||
margin: auto;
|
||||
}
|
||||
|
||||
span {
|
||||
align-self: center;
|
||||
font-size: 1rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
input[type='radio'] {
|
||||
opacity: 0;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
position: absolute;
|
||||
margin: 0;
|
||||
z-index: 9;
|
||||
}
|
||||
|
||||
label {
|
||||
font-weight: bold;
|
||||
position: absolute;
|
||||
left: 50%;
|
||||
top: 20px;
|
||||
max-width: 130px;
|
||||
transform: translateY(-50%) translateX(-50%);
|
||||
text-align: center;
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
text-shadow: 1px 1px 5px rgba($black, 0.25);
|
||||
}
|
||||
|
||||
button.delete {
|
||||
background-color: $red;
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
padding: 3px;
|
||||
border-radius: 100%;
|
||||
position: absolute;
|
||||
right: -15px;
|
||||
top: 0;
|
||||
transform: translateY(-50%);
|
||||
z-index: 1;
|
||||
border: 2px solid $white;
|
||||
|
||||
&:hover {
|
||||
background-color: $dark-red;
|
||||
}
|
||||
}
|
||||
|
||||
span {
|
||||
position: absolute;
|
||||
bottom: 20px;
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
transform: translateY(50%);
|
||||
z-index: 1;
|
||||
text-shadow: 1px 1px 5px rgba($black, 0.25);
|
||||
}
|
||||
|
||||
.sprite-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
margin: auto;
|
||||
|
||||
img {
|
||||
filter: drop-shadow(0 3px 6px rgba($black, 0.25));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.button-wrapper {
|
||||
display: flex;
|
||||
gap: 30px;
|
||||
|
||||
button {
|
||||
padding: 8px 10px 8px 30px;
|
||||
min-width: 100px;
|
||||
position: relative;
|
||||
border-radius: 5px;
|
||||
font-size: 1.25rem;
|
||||
display: flex;
|
||||
gap: 15px;
|
||||
align-items: center;
|
||||
transition: ease-in-out gap 0.2s;
|
||||
|
||||
span {
|
||||
margin: auto;
|
||||
}
|
||||
|
||||
img {
|
||||
height: 30px;
|
||||
filter: drop-shadow(0 4px 6px rgba($black, 0.25));
|
||||
}
|
||||
|
||||
&:disabled {
|
||||
background-color: rgba($cyan, 0.5);
|
||||
cursor: not-allowed;
|
||||
&:hover {
|
||||
gap: 15px;
|
||||
}
|
||||
}
|
||||
|
||||
&:hover {
|
||||
gap: 20px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.modal-title {
|
||||
margin: 0;
|
||||
}
|
||||
}
|
||||
</style>
|
Reference in New Issue
Block a user