safetwitch/src/components/TwitchChat.vue

140 lines
3.6 KiB
Vue

<script lang="ts">
import { ref, type Ref } from 'vue'
import BadgeVue from './ChatBadge.vue'
interface Badge {
id: string,
title: string,
setId: string,
version: string,
images: { [k:string]: string }
}
export default {
props: {
isLive: {
type: Boolean,
default() {
return false
}
},
channelName: {
type: String
}
},
async setup(props) {
let messages: Ref<
{
username: string
channel: string
message: string
messageType: string
tags: Record<string, string>
}[]
> = ref([])
const badgesFetch = await fetch(`${import.meta.env.VITE_BACKEND_URL}/api/badges?channelName=${props.channelName}`)
let badges: Badge[] = await badgesFetch.json()
return {
ws: new WebSocket('ws://localhost:7000'),
messages,
badges,
props,
}
},
mounted() {
const chatList = this.$refs.chatList as Element
const chatStatusMessage = this.$refs.initConnectingStatus as Element
this.ws.onmessage = (message) => {
if (message.data == 'OK') {
chatStatusMessage.textContent = `Connected to ${this.channelName}`
} else {
this.messages.push(JSON.parse(message.data))
this.getBadges(JSON.parse(message.data))
this.clearMessages()
this.scrollToBottom(chatList)
}
}
this.ws.onopen = () => {
this.ws.send('JOIN ' + this.props.channelName?.toLowerCase())
}
},
methods: {
getChat() {
return this.messages
},
scrollToBottom(el: Element) {
el.scrollTop = el.scrollHeight
},
clearMessages() {
if (this.messages.length > 50) {
this.messages.shift
}
},
getBadges(message: { username: string, channel: string, message: string, messageType: string, tags: Record<string, string> }) {
let badgesString = message.tags.badges
if (!badgesString) return;
let badges = badgesString.split(',')
let formatedBadges = badges.map((badgeWithVersion) => {
const [setId, version] = badgeWithVersion.split('/')
return { setId, version }
})
const foundBadges = []
for(let badgeToFind of formatedBadges) {
const badge = this.badges
.filter((badge) => badge.setId === badgeToFind.setId)
.find((badge) => badge.version === badgeToFind.version);
if(badge)
foundBadges.push(badge)
}
return foundBadges
}
},
components: {
BadgeVue
}
}
</script>
<template>
<div v-if="isLive" class="p-3 bg-ctp-crust rounded-lg w-full max-w-[15.625rem] flex flex-col">
<!-- SYSTEM MESSAGES -->
<ul
class="overflow-y-scroll overflow-x-hidden whitespace-pre-wrap h-[46.875rem]"
ref="chatList"
>
<li>
<p ref="initConnectingStatus" class="text-gray-500 text-sm italic">
Connecting to {{ channelName }}.
</p>
</li>
<li v-for="message in getChat()" :key="messages.indexOf(message)">
<div class="text-white inline-flex">
<!-- CHAT MESSAGE-->
<p class="text-sm items-center">
<ul class="inline-flex space-x-1 pr-1">
<li v-for="badge in getBadges(message)" :key="badge.id">
<badge-vue :badge-info="badge"></badge-vue>
</li>
</ul>
<strong
:style="message.tags.color ? `color: ${message.tags.color};` : ``"
class="text-ctp-pink font-bold">
{{ message.username }}</strong>: {{ message.message }}
</p>
</div>
</li>
</ul>
</div>
</template>