Skip to content

Commit bfb2c1d

Browse files
committed
feat(chat): chat message view
1 parent 0da570e commit bfb2c1d

File tree

3 files changed

+79
-20
lines changed

3 files changed

+79
-20
lines changed

packages/chat/client/avatar.vue

+33
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
<template>
2+
<img v-if="src" :src="withProxy(src)" class="b-rd-full select-none"/>
3+
<div v-else
4+
class="b-rd-full bg-gray-500
5+
font-bolder text-18px select-none
6+
flex justify-center items-center">
7+
{{ name && short(name) }}
8+
</div>
9+
</template>
10+
11+
<script setup lang="ts">
12+
13+
import { useRpc } from '@cordisjs/client'
14+
import getWidth from 'string-width'
15+
import type { Data } from '../src'
16+
17+
defineProps<{
18+
src?: string
19+
name?: string
20+
}>()
21+
22+
const data = useRpc<Data>()
23+
24+
function withProxy(url: string) {
25+
return (data.value.proxy ? data.value.proxy + '/' : '') + url
26+
}
27+
28+
function short(name: string) {
29+
if (getWidth(name[0]) > 1) return name[0]
30+
return name.slice(0, 2)
31+
}
32+
33+
</script>

packages/chat/client/index.vue

+44-19
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
<template>
22
<k-layout :title="channelName || '聊天'">
33
<template #left>
4-
<div class="header flex grow-0 shrink-0 box-border">
4+
<div class="layout-left-header flex grow-0 shrink-0 box-border">
55
<template v-if="guildKey">
66
<div class="w-3rem h-full items-center justify-center flex
77
bg-gray-700 bg-op-0 hover:bg-op-100 transition cursor-pointer"
@@ -32,13 +32,7 @@
3232
@click="setGuild(guild)"
3333
@contextmenu.stop="triggerGuild($event, guild)"
3434
>
35-
<img v-if="guild.avatar" :src="withProxy(guild.avatar)" width="48" height="48" class="b-rd-full"/>
36-
<div v-else
37-
class="w-48px h-48px b-rd-full bg-gray-500
38-
font-bolder text-18px
39-
flex justify-center items-center">
40-
{{ short(guild.name!) }}
41-
</div>
35+
<avatar :src="guild.avatar" :name="guild.name" class="w-48px h-48px"/>
4236
<div class="flex flex-col flex-1">
4337
<div>{{ guild.name }}</div>
4438
<div>{{ guild.id }}</div>
@@ -50,10 +44,28 @@
5044
<template v-if="channelId">
5145
<el-scrollbar>
5246
<div v-if="messages?.prev">正在加载更多消息……</div>
53-
<div v-for="message in messages?.data" :key="message.id" class="message"
47+
<div v-for="(message, index) in messages?.data" :key="message.id"
48+
class="relative px-4 py-0 break-words
49+
bg-gray-700 bg-op-0 hover:bg-op-100 transition"
50+
:class="{ 'mt-2': !isSuccessive(index) }"
5451
@contextmenu.stop="triggerMessage($event, message)">
55-
{{ message.id }}
56-
<message-content :content="message.content!"></message-content>
52+
<div class="quote" v-if="message.quote">
53+
{{ message.quote }}
54+
</div>
55+
<template v-if="isSuccessive(index)">
56+
<span>{{ formatTime(new Date(message?.createdAt!)) }}</span>
57+
</template>
58+
<template v-else>
59+
<avatar :src="message.user?.avatar" :name="message.user?.name"
60+
class="w-10 h-10 absolute mt-1.5"/>
61+
<div class="header">
62+
<span class="font-bold lh-relaxed ml-14">{{ message.user?.name }}</span>
63+
<span>{{ formatDateTime(new Date(message?.createdAt!)) }}</span>
64+
</div>
65+
</template>
66+
<message-content :content="message.content!"
67+
class="ml-14 lh-relaxed"
68+
></message-content>
5769
</div>
5870
<div v-if="messages?.next">正在加载更多消息……</div>
5971
</el-scrollbar>
@@ -106,8 +118,8 @@ import { useContext, useRpc, useMenu } from '@cordisjs/client'
106118
import type { Data } from '../src'
107119
import { Universal } from '@satorijs/core'
108120
import { ChatInput, MessageContent } from '@satorijs/components-vue'
121+
import Avatar from './avatar.vue'
109122
110-
const data = useRpc<Data>()
111123
const ctx = useContext()
112124
113125
const platform = ref<string>()
@@ -139,12 +151,10 @@ ctx.action('chat.message.inspect', async ({ chat }) => {
139151
showMessage.value = chat.message
140152
})
141153
142-
function short(name: string) {
143-
return name.slice(0, 2)
144-
}
145-
146-
function withProxy(url: string) {
147-
return (data.value.proxy ? data.value.proxy + '/' : '') + url
154+
function isSuccessive(index: number) {
155+
const curr = messages.value?.data[index]
156+
const prev = messages.value?.data[index - 1]
157+
return curr && prev && !curr.quote && curr.user?.id === prev.user?.id
148158
}
149159
150160
async function setGuild(guild?: Universal.Guild & { platform: string; assignees: string[] }) {
@@ -170,11 +180,26 @@ function handleSend(content: string) {
170180
return ctx.bots[ctx.chat.guilds.value[guildKey.value!].assignees[0]].sendMessage(channelId.value!, content)
171181
}
172182
183+
function formatTime(date: Date) {
184+
if (Number.isNaN(+date)) return ''
185+
return `${date.getHours()}:${date.getMinutes().toString().padStart(2, '0')}:${date.getSeconds().toString().padStart(2, '0')}`
186+
}
187+
188+
function formatDateTime(date: Date) {
189+
if (Number.isNaN(+date)) return ''
190+
const now = new Date()
191+
const time = formatTime(date)
192+
if (date.toLocaleDateString() === now.toLocaleDateString()) {
193+
return time
194+
}
195+
return `${date.getFullYear()}-${date.getMonth() + 1}-${date.getDate()} ${time}`
196+
}
197+
173198
</script>
174199

175200
<style lang="scss" scoped>
176201
177-
.header {
202+
.layout-left-header {
178203
height: var(--header-height);
179204
border-bottom: var(--k-color-divider-dark) 1px solid;
180205
}

packages/chat/package.json

+2-1
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@
5454
"@satorijs/plugin-database": "^0.1.1"
5555
},
5656
"dependencies": {
57-
"cosmokit": "^1.6.2"
57+
"cosmokit": "^1.6.2",
58+
"string-width": "^7.1.0"
5859
}
5960
}

0 commit comments

Comments
 (0)