|
| 1 | +<script setup lang="ts"> |
| 2 | +const { user, fetch: refreshSession } = useUserSession() |
| 3 | +const { data, send, open, status } = useWebSocket(`/api/chatroom`, { immediate: false }) |
| 4 | +
|
| 5 | +const chatContainer = ref<HTMLDivElement | null>(null) |
| 6 | +const messages = ref<{ id: string, username: string, content: string }[]>([]) |
| 7 | +watch(data, async (event) => { |
| 8 | + const data = await typeof event === 'string' ? event : await event.text() |
| 9 | + messages.value.push(data[0] === '{' ? JSON.parse(data) : data) |
| 10 | + await nextTick() |
| 11 | + if (chatContainer.value) { |
| 12 | + chatContainer.value.scrollTop = chatContainer.value.scrollHeight |
| 13 | + } |
| 14 | +}) |
| 15 | +
|
| 16 | +async function enterChat() { |
| 17 | + await $fetch('/api/login', { |
| 18 | + method: 'POST', |
| 19 | + body: { username: username.value } |
| 20 | + }) |
| 21 | + await refreshSession() |
| 22 | + open() |
| 23 | +} |
| 24 | +
|
| 25 | +const username = ref(user.value?.username || '') |
| 26 | +const message = ref('') |
| 27 | +
|
| 28 | +onMounted(() => { |
| 29 | + if (user.value?.username) { |
| 30 | + console.log('open') |
| 31 | + open() |
| 32 | + } |
| 33 | +}) |
| 34 | +
|
| 35 | +function sendMessage() { |
| 36 | + send(JSON.stringify({ |
| 37 | + username: username.value, |
| 38 | + content: message.value |
| 39 | + })) |
| 40 | + message.value = '' |
| 41 | +} |
| 42 | +</script> |
| 43 | + |
| 44 | +<template> |
| 45 | + <UCard v-if="user?.username && status === 'OPEN'"> |
| 46 | + <div ref="chatContainer" class="h-full max-h-[400px] overflow-auto"> |
| 47 | + <div v-for="(msg, index) in messages" :key="msg.id" class="flex flex-col" :class="{ 'pt-2': index > 0 && msg.username !== messages[index - 1]?.username }"> |
| 48 | + <div :class="msg.username === user.username ? 'pl-8 ml-auto' : 'pr-8 mr-auto'"> |
| 49 | + <!-- only show username if previous one is not from the same user --> |
| 50 | + <div v-if="index < 1 || msg.username !== messages[index - 1]?.username" class="text-xs text-gray-500"> |
| 51 | + {{ msg.username }} |
| 52 | + </div> |
| 53 | + <p |
| 54 | + class="p-2 mt-1 text-sm rounded-lg text-smp-2 whitespace-pre-line" |
| 55 | + :class="msg.username === user.username ? 'text-white bg-blue-400' : 'text-gray-700 bg-gray-200'" |
| 56 | + > |
| 57 | + {{ msg.content }} |
| 58 | + </p> |
| 59 | + </div> |
| 60 | + </div> |
| 61 | + </div> |
| 62 | + <form class="flex items-center w-full pt-4 gap-2" @submit.prevent="sendMessage"> |
| 63 | + <UInput v-model="message" placeholder="Send a message..." class="w-full" /> |
| 64 | + <UButton icon="i-heroicons-paper-airplane" type="submit" color="black" /> |
| 65 | + </form> |
| 66 | + </UCard> |
| 67 | + <UCard v-else> |
| 68 | + <form class="flex items-center gap-2" @submit.prevent="enterChat"> |
| 69 | + <UInput v-model="username" placeholder="Enter your username" name="username" /> |
| 70 | + <UButton color="black" :disabled="!username.trim()" :loading="status === 'CONNECTING'" type="submit"> |
| 71 | + Enter Chat |
| 72 | + </UButton> |
| 73 | + </form> |
| 74 | + </UCard> |
| 75 | +</template> |
0 commit comments