2026-03-02 14:20:34 +00:00
|
|
|
<template>
|
|
|
|
|
<div
|
2026-03-02 14:26:22 +00:00
|
|
|
class="flex animate-fade-up-fast"
|
2026-03-02 14:20:34 +00:00
|
|
|
:class="isUser ? 'justify-end' : 'justify-start'"
|
|
|
|
|
:style="{ animationDelay: `${index * 30}ms` }"
|
|
|
|
|
>
|
|
|
|
|
<div
|
2026-03-02 14:26:22 +00:00
|
|
|
class="max-w-[85%] md:max-w-[70%] rounded-2xl px-4 py-3 transition-all duration-300"
|
2026-03-02 14:20:34 +00:00
|
|
|
:class="bubbleClasses"
|
|
|
|
|
>
|
2026-03-02 14:26:22 +00:00
|
|
|
<p class="text-sm leading-relaxed whitespace-pre-wrap break-words text-white/90">{{ message.content }}</p>
|
2026-03-02 14:20:34 +00:00
|
|
|
<div class="flex items-center gap-2 mt-1.5">
|
2026-03-02 14:26:22 +00:00
|
|
|
<span class="text-[10px] text-white/30 select-none">{{ formattedTime }}</span>
|
|
|
|
|
<span v-if="isUser && message.status" class="text-[10px] text-white/20">
|
2026-03-02 14:20:34 +00:00
|
|
|
{{ message.status === 'sent' ? '✓' : message.status === 'delivered' ? '✓✓' : '' }}
|
|
|
|
|
</span>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</template>
|
|
|
|
|
|
|
|
|
|
<script setup lang="ts">
|
|
|
|
|
import { computed } from 'vue'
|
|
|
|
|
import type { Message } from '@aiui/core/types/message'
|
|
|
|
|
|
|
|
|
|
const props = defineProps<{
|
|
|
|
|
message: Message
|
|
|
|
|
index: number
|
|
|
|
|
}>()
|
|
|
|
|
|
|
|
|
|
const isUser = computed(() => props.message.role === 'user')
|
|
|
|
|
|
|
|
|
|
const bubbleClasses = computed(() =>
|
|
|
|
|
isUser.value
|
2026-03-02 14:26:22 +00:00
|
|
|
? 'glass-strong rounded-br-md'
|
|
|
|
|
: 'glass-card rounded-bl-md'
|
2026-03-02 14:20:34 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
|
|
const formattedTime = computed(() => {
|
|
|
|
|
const d = new Date(props.message.timestamp)
|
|
|
|
|
return d.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' })
|
|
|
|
|
})
|
|
|
|
|
</script>
|