1
0
forked from noxious/client

123 lines
3.8 KiB
Vue

<template>
<div class="w-full md:min-w-[350px] max-w-[750px] flex flex-col">
<div ref="chatWindow" class="w-full overflow-auto h-32 mb-5 bg-gray-300/80 rounded-lg border-2 border-solid border-cyan-200" v-show="gameStore.isChatOpen">
<div v-for="message in chats" class="flex-col py-2 items-center p-3">
<span class="text-ellipsis overflow-hidden whitespace-nowrap text-sm">{{ message.character.name }}</span>
<p class="text-gray-50 m-0">{{ message.message }}</p>
</div>
</div>
<div class="w-full flex">
<input
class="w-full h-12 rounded-lg text-lg px-4 py-0 bg-gray-300/80 border-2 border-solid border-cyan-200 text-gray-50 bg-[url('/assets/icons/submit-icon.svg')] bg-no-repeat bg-[right_25px_center] bg-[length:30px] focus:outline-none focus:ring-0 focus:border-cyan-800"
placeholder="Type something..."
v-model="message"
@keypress="handleKeyPress"
@submit="handleSubmit"
/>
</div>
</div>
</template>
<script setup lang="ts">
import { onBeforeUnmount, onMounted, ref, nextTick } from 'vue'
import { useGameStore } from '@/stores/gameStore'
import type { Character, ChatMessage } from '@/types'
import { useZoneStore } from '@/stores/zoneStore'
import { useScene } from 'phavuer'
const scene = useScene()
const gameStore = useGameStore()
const zoneStore = useZoneStore()
const message = ref('')
const chats = ref([] as ChatMessage[])
const chatWindow = ref<HTMLElement | null>(null)
const sendMessage = () => {
if (!message.value.trim()) return
gameStore.connection?.emit('chat:send_message', { message: message.value }, (response: boolean) => {})
message.value = ''
}
const handleSubmit = (event: Event) => {
event.preventDefault()
sendMessage()
}
const handleKeyPress = (event: KeyboardEvent) => {
if (event.key === 'Enter' && !event.shiftKey) {
event.preventDefault()
sendMessage()
}
}
const scrollToBottom = () => {
nextTick(() => {
if (chatWindow.value) {
chatWindow.value.scrollTop = chatWindow.value.scrollHeight
}
})
}
gameStore.connection?.on('chat:message', (data: ChatMessage) => {
chats.value.push(data)
scrollToBottom()
if (!zoneStore.characterLoaded) return
const charChatContainer = scene.children.getByName(data.character.name + '_chatContainer') as Phaser.GameObjects.Container
if (!charChatContainer) return
const chatBubble = charChatContainer.getByName(data.character.name + '_chatBubble') as Phaser.GameObjects.Container
const chatText = charChatContainer.getByName(data.character.name + '_chatText') as Phaser.GameObjects.Text
if (!chatText || !chatBubble) return
function calculateTextWidth(text: string, font: string, fontSize: number): number {
// Create a canvas element
const canvas = document.createElement('canvas')
const context = canvas.getContext('2d')
if (!context) {
throw new Error('Unable to create canvas context')
}
// Set the font
context.font = `${fontSize}px ${font}`
// Measure the text width
const metrics = context.measureText(text)
return metrics.width
}
chatBubble.width = calculateTextWidth(data.message.substring(0, 90), 'Arial', 13) + 30
// setText but with max. char limit of 90
chatText.setText(data.message.substring(0, 90))
charChatContainer.setVisible(true)
/**
* Hide chat bubble after a few seconds
*/
// Clear any existing hide timer
if (charChatContainer.getData('hideTimer')) {
clearTimeout(charChatContainer.getData('hideTimer'))
}
// Set a new hide timer
const hideTimer = setTimeout(() => {
charChatContainer.setVisible(false)
}, 3000)
// Store the timer on the container itself
charChatContainer.setData('hideTimer', hideTimer)
})
scrollToBottom()
onBeforeUnmount(() => {
gameStore.connection?.off('chat:message')
})
</script>