Fixed characters not showing after logging in, added loading screen before showing characters, worked on GM tools
This commit is contained in:
parent
2f7153fbfe
commit
3e003962dc
1
public/assets/icons/loading-icon1.svg
Normal file
1
public/assets/icons/loading-icon1.svg
Normal file
@ -0,0 +1 @@
|
|||||||
|
<svg width="24" height="24" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><style>.spinner_z9k8{transform-origin:center;animation:spinner_StKS .75s infinite linear}@keyframes spinner_StKS{100%{transform:rotate(360deg)}}</style><path d="M12,1A11,11,0,1,0,23,12,11,11,0,0,0,12,1Zm0,19a8,8,0,1,1,8-8A8,8,0,0,1,12,20Z" opacity=".25"/><path d="M12,4a8,8,0,0,1,7.89,6.7A1.53,1.53,0,0,0,21.38,12h0a1.5,1.5,0,0,0,1.48-1.75,11,11,0,0,0-21.72,0A1.5,1.5,0,0,0,2.62,12h0a1.53,1.53,0,0,0,1.49-1.3A8,8,0,0,1,12,4Z" class="spinner_z9k8"/></svg>
|
After Width: | Height: | Size: 537 B |
1
public/assets/icons/loading-icon2.svg
Normal file
1
public/assets/icons/loading-icon2.svg
Normal file
@ -0,0 +1 @@
|
|||||||
|
<svg width="24" height="24" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><style>.spinner_qM83{animation:spinner_8HQG 1.05s infinite}.spinner_oXPr{animation-delay:.1s}.spinner_ZTLf{animation-delay:.2s}@keyframes spinner_8HQG{0%,57.14%{animation-timing-function:cubic-bezier(0.33,.66,.66,1);transform:translate(0)}28.57%{animation-timing-function:cubic-bezier(0.33,0,.66,.33);transform:translateY(-6px)}100%{transform:translate(0)}}</style><circle class="spinner_qM83" cx="4" cy="12" r="3"/><circle class="spinner_qM83 spinner_oXPr" cx="12" cy="12" r="3"/><circle class="spinner_qM83 spinner_ZTLf" cx="20" cy="12" r="3"/></svg>
|
After Width: | Height: | Size: 635 B |
@ -18,13 +18,12 @@ import Game from '@/components/Game.vue'
|
|||||||
const screen: Ref<string> = ref('login')
|
const screen: Ref<string> = ref('login')
|
||||||
const socket = useSocketStore()
|
const socket = useSocketStore()
|
||||||
|
|
||||||
socket.$subscribe(
|
socket.$subscribe((mutation, state) => {
|
||||||
(mutation, state) => {
|
|
||||||
if (!state.connection) {
|
if (!state.connection) {
|
||||||
screen.value = 'login'
|
screen.value = 'login'
|
||||||
}
|
}
|
||||||
|
|
||||||
if (state.connection) {
|
if (state.token && state.connection) {
|
||||||
screen.value = 'characters'
|
screen.value = 'characters'
|
||||||
|
|
||||||
if (state.character) {
|
if (state.character) {
|
||||||
|
@ -16,12 +16,12 @@ body {
|
|||||||
}
|
}
|
||||||
|
|
||||||
h1, h2, h3, h4, h5, h6, button, a {
|
h1, h2, h3, h4, h5, h6, button, a {
|
||||||
font-family: "Poppins";
|
font-family: "Poppins", serif;
|
||||||
color: $white;
|
color: $white;
|
||||||
}
|
}
|
||||||
|
|
||||||
p, span, li, label {
|
p, span, li, label {
|
||||||
font-family: "Inter";
|
font-family: "Inter", serif;
|
||||||
color: $white;
|
color: $white;
|
||||||
}
|
}
|
||||||
button, a {
|
button, a {
|
||||||
@ -37,6 +37,10 @@ button, input {
|
|||||||
button {
|
button {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
|
|
||||||
|
&.w-full {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
&.btn-cyan {
|
&.btn-cyan {
|
||||||
background-color: rgba($cyan, 0.5);
|
background-color: rgba($cyan, 0.5);
|
||||||
border: 1px solid $white;
|
border: 1px solid $white;
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="character-select-screen">
|
<div class="character-select-screen">
|
||||||
<div class="ui-wrapper">
|
<div class="ui-wrapper">
|
||||||
<div class="characters-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 }">
|
<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" />
|
<input type="radio" :id="character.id" name="character" :value="character.id" v-model="selected_character" />
|
||||||
<label :for="character.id">{{ character.name }}</label>
|
<label :for="character.id">{{ character.name }}</label>
|
||||||
@ -23,8 +23,13 @@
|
|||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div v-else>
|
||||||
|
<div class="loading-spinner">
|
||||||
|
<img src="/assets/icons/loading-icon1.svg" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="button-wrapper">
|
<div class="button-wrapper" v-if="!isLoading">
|
||||||
<button class="btn-cyan" :disabled="!selected_character" @click="select_character()">
|
<button class="btn-cyan" :disabled="!selected_character" @click="select_character()">
|
||||||
PLAY
|
PLAY
|
||||||
<img draggable="false" src="/assets/icons/arrow.svg">
|
<img draggable="false" src="/assets/icons/arrow.svg">
|
||||||
@ -55,18 +60,26 @@
|
|||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { useSocketStore } from '@/stores/socket'
|
import { useSocketStore } from '@/stores/socket'
|
||||||
import { ref } from 'vue'
|
import { onBeforeMount, onMounted, ref } from 'vue'
|
||||||
import Modal from '@/components/utilities/Modal.vue'
|
import Modal from '@/components/utilities/Modal.vue'
|
||||||
import {type Character as CharacterT} from '@/types'
|
import {type Character as CharacterT} from '@/types'
|
||||||
|
|
||||||
|
const isLoading = ref(true)
|
||||||
const characters = ref([])
|
const characters = ref([])
|
||||||
const socket = useSocketStore()
|
const socket = useSocketStore();
|
||||||
|
|
||||||
// Fetch characters
|
// Fetch characters
|
||||||
socket.getConnection.on('character:list', (data: any) => {
|
socket.getConnection.on('character:list', (data: any) => {
|
||||||
characters.value = data
|
characters.value = data
|
||||||
})
|
})
|
||||||
socket.getConnection.emit('character:list')
|
|
||||||
|
onMounted(() => {
|
||||||
|
// wait 1.5 sec
|
||||||
|
setTimeout(() => {
|
||||||
|
socket.getConnection.emit('character:list')
|
||||||
|
isLoading.value = false
|
||||||
|
}, 1000)
|
||||||
|
});
|
||||||
|
|
||||||
// Select character logics
|
// Select character logics
|
||||||
const selected_character = ref(null)
|
const selected_character = ref(null)
|
||||||
@ -123,6 +136,14 @@ function create() {
|
|||||||
content: '';
|
content: '';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.loading-spinner img {
|
||||||
|
width: 5rem;
|
||||||
|
// css color
|
||||||
|
filter: invert(1);
|
||||||
|
// white
|
||||||
|
filter: invert(80%);
|
||||||
|
}
|
||||||
|
|
||||||
.characters-wrapper {
|
.characters-wrapper {
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
|
@ -32,6 +32,7 @@ import { login, register } from '@/services/authentication'
|
|||||||
import { useNotificationStore } from '@/stores/notifications'
|
import { useNotificationStore } from '@/stores/notifications'
|
||||||
import ZoneEditor from '@/components/utilities/zoneEditor/ZoneEditor.vue'
|
import ZoneEditor from '@/components/utilities/zoneEditor/ZoneEditor.vue'
|
||||||
import Modal from '@/components/utilities/Modal.vue'
|
import Modal from '@/components/utilities/Modal.vue'
|
||||||
|
import { useSocketStore } from '@/stores/socket'
|
||||||
|
|
||||||
const bgm = ref('bgm')
|
const bgm = ref('bgm')
|
||||||
if (bgm.value.paused) {
|
if (bgm.value.paused) {
|
||||||
@ -39,6 +40,7 @@ if (bgm.value.paused) {
|
|||||||
window.addEventListener('keydown', () => bgm.value.play())
|
window.addEventListener('keydown', () => bgm.value.play())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const socket = useSocketStore()
|
||||||
const notifications = useNotificationStore()
|
const notifications = useNotificationStore()
|
||||||
const username = ref('')
|
const username = ref('')
|
||||||
const password = ref('')
|
const password = ref('')
|
||||||
@ -55,7 +57,11 @@ async function loginFunc() {
|
|||||||
|
|
||||||
if (response.success === undefined) {
|
if (response.success === undefined) {
|
||||||
notifications.addNotification({ message: response.error })
|
notifications.addNotification({ message: response.error })
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
socket.setToken(response.token)
|
||||||
|
socket.initConnection();
|
||||||
}
|
}
|
||||||
|
|
||||||
async function registerFunc() {
|
async function registerFunc() {
|
||||||
@ -70,7 +76,11 @@ async function registerFunc() {
|
|||||||
|
|
||||||
if (response.success === undefined) {
|
if (response.success === undefined) {
|
||||||
notifications.addNotification({ message: response.error })
|
notifications.addNotification({ message: response.error })
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
socket.setToken(response.token)
|
||||||
|
socket.initConnection();
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
@ -45,9 +45,7 @@ const properties = defineProps({
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
watch(
|
watch(() => properties.isModalOpen, (value) => {
|
||||||
() => properties.isModalOpen,
|
|
||||||
(value) => {
|
|
||||||
isModalOpenRef.value = value
|
isModalOpenRef.value = value
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
@ -124,6 +122,16 @@ const stopDrag = () => {
|
|||||||
isDragging.value = false
|
isDragging.value = false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
watch(() => properties.modalWidth, (value) => {
|
||||||
|
width.value = value
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
watch(() => properties.modalHeight, (value) => {
|
||||||
|
height.value = value
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
addEventListener('mousemove', drag)
|
addEventListener('mousemove', drag)
|
||||||
addEventListener('mouseup', stopDrag)
|
addEventListener('mouseup', stopDrag)
|
||||||
@ -142,13 +150,11 @@ onUnmounted(() => {
|
|||||||
|
|
||||||
|
|
||||||
// Make sure modal doesn't go off screen
|
// Make sure modal doesn't go off screen
|
||||||
watch(
|
watch(() => x.value, (value) => {
|
||||||
() => x.value, (value) => {
|
|
||||||
if (value < 0) { x.value = 0 } else if (value + width.value > window.innerWidth) { x.value = window.innerWidth - width.value }
|
if (value < 0) { x.value = 0 } else if (value + width.value > window.innerWidth) { x.value = window.innerWidth - width.value }
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
watch(
|
watch(() => y.value, (value) => {
|
||||||
() => y.value, (value) => {
|
|
||||||
if (value < 0) { y.value = 0 } else if (value + height.value > window.innerHeight) { y.value = window.innerHeight - height.value }
|
if (value < 0) { y.value = 0 } else if (value + height.value > window.innerHeight) { y.value = window.innerHeight - height.value }
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
@ -1,10 +1,15 @@
|
|||||||
<template>
|
<template>
|
||||||
<Modal :isModalOpen="true">
|
<Modal :isModalOpen="true" :closable="false" :modal-width="200" :modal-height="260">
|
||||||
<template #modalHeader>
|
<template #modalHeader>
|
||||||
<h3 class="modal-title">GM tools</h3>
|
<h3 class="modal-title">GM tools</h3>
|
||||||
</template>
|
</template>
|
||||||
<template #modalBody>
|
<template #modalBody>
|
||||||
<p></p>
|
<div class="content">
|
||||||
|
<button class="btn-cyan w-full" type="button">Zone manager</button>
|
||||||
|
<button class="btn-cyan w-full" type="button">Player manager</button>
|
||||||
|
<button class="btn-cyan w-full" type="button">Item manager</button>
|
||||||
|
<button class="btn-cyan w-full" type="button">NPC manager</button>
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</Modal>
|
</Modal>
|
||||||
</template>
|
</template>
|
||||||
@ -12,3 +17,11 @@
|
|||||||
import ZoneEditor from '@/components/utilities/zoneEditor/ZoneEditor.vue'
|
import ZoneEditor from '@/components/utilities/zoneEditor/ZoneEditor.vue'
|
||||||
import Modal from '@/components/utilities/Modal.vue'
|
import Modal from '@/components/utilities/Modal.vue'
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
.content {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 0.8rem;
|
||||||
|
}
|
||||||
|
</style>
|
@ -7,8 +7,7 @@ export async function register(username: string, password: string, socketStore =
|
|||||||
try {
|
try {
|
||||||
const response = await axios.post(`${config.server_endpoint}/register`, { username, password })
|
const response = await axios.post(`${config.server_endpoint}/register`, { username, password })
|
||||||
useCookies().set('token', response.data.token as string)
|
useCookies().set('token', response.data.token as string)
|
||||||
await socketStore.setupSocketConnection()
|
return { success: true, token: response.data.token}
|
||||||
return { success: true }
|
|
||||||
} catch (error: any) {
|
} catch (error: any) {
|
||||||
return { error: error.response.data.message }
|
return { error: error.response.data.message }
|
||||||
}
|
}
|
||||||
@ -18,8 +17,7 @@ export async function login(username: string, password: string, socketStore = us
|
|||||||
try {
|
try {
|
||||||
const response = await axios.post(`${config.server_endpoint}/login`, { username, password })
|
const response = await axios.post(`${config.server_endpoint}/login`, { username, password })
|
||||||
useCookies().set('token', response.data.token as string)
|
useCookies().set('token', response.data.token as string)
|
||||||
await socketStore.setupSocketConnection()
|
return { success: true, token: response.data.token}
|
||||||
return { success: true }
|
|
||||||
} catch (error: any) {
|
} catch (error: any) {
|
||||||
return { error: error.response.data.message }
|
return { error: error.response.data.message }
|
||||||
}
|
}
|
||||||
|
@ -6,17 +6,19 @@ import type { Character, User } from '@/types'
|
|||||||
|
|
||||||
export const useSocketStore: StoreDefinition = defineStore('socket', {
|
export const useSocketStore: StoreDefinition = defineStore('socket', {
|
||||||
state: () => ({
|
state: () => ({
|
||||||
|
token: '' as string | null,
|
||||||
connection: null as Socket | null,
|
connection: null as Socket | null,
|
||||||
user: null as User | null,
|
user: null as User | null,
|
||||||
character: null as Character | null
|
character: null as Character | null
|
||||||
}),
|
}),
|
||||||
getters: {
|
getters: {
|
||||||
|
getToken: (state: any) => state.token as string,
|
||||||
getConnection: (state: any) => state.connection as Socket,
|
getConnection: (state: any) => state.connection as Socket,
|
||||||
getUser: (state: any) => state.user as User,
|
getUser: (state: any) => state.user as User,
|
||||||
getCharacter: (state: any) => state.character as Character
|
getCharacter: (state: any) => state.character as Character
|
||||||
},
|
},
|
||||||
actions: {
|
actions: {
|
||||||
setupSocketConnection() {
|
initConnection() {
|
||||||
this.connection = io(config.server_endpoint, {
|
this.connection = io(config.server_endpoint, {
|
||||||
withCredentials: true,
|
withCredentials: true,
|
||||||
transports: ['websocket'],
|
transports: ['websocket'],
|
||||||
@ -27,7 +29,7 @@ export const useSocketStore: StoreDefinition = defineStore('socket', {
|
|||||||
this.connection.emit('login')
|
this.connection.emit('login')
|
||||||
|
|
||||||
// set user
|
// set user
|
||||||
this.connection.on('login', (user: User) => {
|
this.connection.on('logged_in', (user: User) => {
|
||||||
this.setUser(user)
|
this.setUser(user)
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -43,11 +45,15 @@ export const useSocketStore: StoreDefinition = defineStore('socket', {
|
|||||||
this.connection.disconnect()
|
this.connection.disconnect()
|
||||||
this.connection = null
|
this.connection = null
|
||||||
|
|
||||||
|
this.token = null
|
||||||
this.user = null
|
this.user = null
|
||||||
this.character = null
|
this.character = null
|
||||||
|
|
||||||
useCookies().remove('token')
|
useCookies().remove('token')
|
||||||
},
|
},
|
||||||
|
setToken(token: string) {
|
||||||
|
this.token = token
|
||||||
|
},
|
||||||
setUser(user: User | null) {
|
setUser(user: User | null) {
|
||||||
this.user = user
|
this.user = user
|
||||||
},
|
},
|
||||||
|
Loading…
x
Reference in New Issue
Block a user