style(stage-*): bubble styles

This commit is contained in:
Neko Ayaka
2025-09-17 02:25:13 +08:00
parent bb98376136
commit 58616d9edb
4 changed files with 52 additions and 51 deletions
@@ -1,6 +1,4 @@
<script setup lang="ts">
import type { CommonContentPart } from '@xsai/shared-chat'
import { MarkdownRenderer } from '@proj-airi/stage-ui/components'
import { useChatStore } from '@proj-airi/stage-ui/stores/chat'
import { storeToRefs } from 'pinia'
@@ -40,8 +38,9 @@ onTokenLiteral(async () => {
<div v-for="(message, index) in messages" :key="index" mb-2>
<div v-if="message.role === 'error'" flex mr="12">
<div
flex="~ col" border="2 solid violet-200/50 dark:violet-500/50" shadow="md violet-200/50 dark:none"
min-w-20 rounded-lg px-2 py-1 h="unset <sm:fit" bg="<md:violet-500/25"
flex="~ col" shadow="md violet-900/50 dark:none"
min-w-20 rounded-lg px-2 py-1 h="unset <sm:fit"
class="bg-violet-50/80 <md:bg-violet-500/25 dark:bg-violet-900/80"
>
<div flex="~ row" gap-2>
<div flex-1>
@@ -58,15 +57,16 @@ onTokenLiteral(async () => {
/>
</div>
</div>
<div v-if="message.role === 'assistant' && message.content !== ''" flex mr="12">
<div v-if="message.role === 'assistant'" flex mr="12">
<div
flex="~ col" border="2 solid primary-200/50 dark:primary-500/50" shadow="md primary-200/50 dark:none" min-w-20
rounded-lg px-2 py-1 h="unset <sm:fit" bg="<md:primary-500/25"
flex="~ col" shadow="sm primary-200/50 dark:none" min-w-20
rounded-lg px-2 py-1 h="unset <sm:fit"
class="bg-primary-50/80 <md:bg-primary-500/25 dark:bg-primary-900/80"
>
<div>
<span text-xs text="primary-400/90 dark:primary-600/90" font-normal class="inline <sm:hidden">{{ t('stage.chat.message.character-name.airi') }}</span>
</div>
<div class="break-words" text="xs primary-400">
<div v-if="message.content" class="break-words" text="primary-700 dark:primary-200">
<div v-for="(slice, sliceIndex) in message.slices" :key="sliceIndex">
<div v-if="slice.type === 'tool-call'">
<div
@@ -82,45 +82,38 @@ onTokenLiteral(async () => {
/>
</div>
</div>
<div v-else-if="index === messages.length - 1 && !message.content" i-eos-icons:three-dots-loading />
</div>
</div>
<div v-else-if="message.role === 'user'" flex="~ row-reverse" ml="12">
<div
flex="~ col" border="2 solid cyan-200/50 dark:cyan-500/50" shadow="md cyan-200/50 dark:none" px="2"
h="unset <sm:fit" min-w-20 rounded-lg px-2 py-1 bg="<md:cyan-500/25"
flex="~ col" shadow="sm cyan-200/50 dark:none" px="2"
h="unset <sm:fit" min-w-20 rounded-lg px-2 py-1
class="bg-cyan-50/80 <md:bg-cyan-500/25 dark:bg-cyan-900/80"
>
<div>
<span text-xs text="cyan-400/90 dark:cyan-600/90" font-normal class="inline <sm:hidden">{{ t('stage.chat.message.character-name.you') }}</span>
</div>
<div v-if="Array.isArray(message.content)" class="flex flex-col gap-2">
<template v-for="(part, partIndex) in (message.content as CommonContentPart[])" :key="partIndex">
<MarkdownRenderer
v-if="part.type === 'text' && part.text"
:content="part.text"
class="break-words"
text="base <sm:xs"
/>
<img v-if="part.type === 'image_url'" :src="part.image_url.url" class="max-w-full rounded-lg">
</template>
</div>
<MarkdownRenderer
v-else-if="typeof message.content === 'string'"
:content="message.content"
v-if="message.content"
:content="message.content as string"
class="break-words"
text="base <sm:xs"
/>
<div v-else />
</div>
</div>
</div>
<div v-if="sending" flex mr="12">
<div
flex="~ col" border="2 solid primary-200/50 dark:primary-500/50" shadow="md primary-200/50 dark:none" min-w-20
rounded-lg px-2 py-1 h="unset <sm:fit" bg="<md:primary-500/25"
flex="~ col" shadow="sm primary-200/50 dark:none" min-w-20
rounded-lg px-2 py-1 h="unset <sm:fit"
class="bg-primary-50/80 <md:bg-primary-500/25 dark:bg-primary-900/80"
>
<div>
<span text-xs text="primary-400/90 dark:primary-600/90" font-normal class="inline <sm:hidden">{{ t('stage.chat.message.character-name.airi') }}</span>
</div>
<div v-if="streamingMessage.content" class="break-words" text="xs primary-400">
<div v-if="streamingMessage.content" class="break-words" text="primary-700 dark:primary-200">
<div v-for="(slice, sliceIndex) in streamingMessage.slices" :key="sliceIndex">
<div v-if="slice.type === 'tool-call'">
<div
@@ -40,8 +40,9 @@ onTokenLiteral(async () => {
<div v-for="(message, index) in messages" :key="index" mb-2>
<div v-if="message.role === 'error'" flex mr="12">
<div
flex="~ col" border="2 solid violet-200/50 dark:violet-500/50" shadow="md violet-200/50 dark:none"
min-w-20 rounded-lg px-2 py-1 h="unset <sm:fit" bg="<md:violet-500/25"
flex="~ col" shadow="md violet-900/50 dark:none"
min-w-20 rounded-lg px-2 py-1 h="unset <sm:fit"
class="bg-violet-50/80 <md:bg-violet-500/25 dark:bg-violet-900/80"
>
<div flex="~ row" gap-2>
<div flex-1>
@@ -60,13 +61,14 @@ onTokenLiteral(async () => {
</div>
<div v-if="message.role === 'assistant' && message.content !== ''" flex mr="12">
<div
flex="~ col" border="2 solid primary-200/50 dark:primary-500/50" shadow="md primary-200/50 dark:none" min-w-20
rounded-lg px-2 py-1 h="unset <sm:fit" bg="<md:primary-500/25"
flex="~ col" shadow="sm primary-200/50 dark:none" min-w-20
rounded-lg px-2 py-1 h="unset <sm:fit"
class="bg-primary-50/80 <md:bg-primary-500/25 dark:bg-primary-900/80"
>
<div>
<span text-xs text="primary-400/90 dark:primary-600/90" font-normal class="inline <sm:hidden">{{ t('stage.chat.message.character-name.airi') }}</span>
</div>
<div class="break-words" text="xs primary-400">
<div class="break-words" text="primary-700 dark:primary-200">
<div v-for="(slice, sliceIndex) in message.slices" :key="sliceIndex">
<div v-if="slice.type === 'tool-call'">
<div
@@ -86,8 +88,9 @@ onTokenLiteral(async () => {
</div>
<div v-else-if="message.role === 'user'" flex="~ row-reverse" ml="12">
<div
flex="~ col" border="2 solid cyan-200/50 dark:cyan-500/50" shadow="md cyan-200/50 dark:none" px="2"
h="unset <sm:fit" min-w-20 rounded-lg px-2 py-1 bg="<md:cyan-500/25"
flex="~ col" shadow="sm cyan-200/50 dark:none" px="2"
h="unset <sm:fit" min-w-20 rounded-lg px-2 py-1
class="bg-cyan-50/80 <md:bg-cyan-500/25 dark:bg-cyan-900/80"
>
<div>
<span text-xs text="cyan-400/90 dark:cyan-600/90" font-normal class="inline <sm:hidden">{{ t('stage.chat.message.character-name.you') }}</span>
@@ -114,13 +117,14 @@ onTokenLiteral(async () => {
</div>
<div v-if="sending" flex mr="12">
<div
flex="~ col" border="2 solid primary-200/50 dark:primary-500/50" shadow="md primary-200/50 dark:none" min-w-20
rounded-lg px-2 py-1 h="unset <sm:fit" bg="<md:primary-500/25"
flex="~ col" shadow="sm primary-200/50 dark:none" min-w-20
rounded-lg px-2 py-1 h="unset <sm:fit"
class="bg-primary-50/80 <md:bg-primary-500/25 dark:bg-primary-900/80"
>
<div>
<span text-xs text="primary-400/90 dark:primary-600/90" font-normal class="inline <sm:hidden">{{ t('stage.chat.message.character-name.airi') }}</span>
</div>
<div v-if="streamingMessage.content" class="break-words" text="xs primary-400">
<div v-if="streamingMessage.content" class="break-words" text="primary-700 dark:primary-200">
<div v-for="(slice, sliceIndex) in streamingMessage.slices" :key="sliceIndex">
<div v-if="slice.type === 'tool-call'">
<div
@@ -41,8 +41,9 @@ onTokenLiteral(async () => {
<div v-for="(message, index) in messages" :key="index" mb-2>
<div v-if="message.role === 'error'" flex mr="12">
<div
flex="~ col" border="2 solid violet-200/50 dark:violet-500/50" shadow="md violet-200/50 dark:none"
min-w-20 rounded-lg px-2 py-1 h="unset <sm:fit" bg="<md:violet-500/25"
flex="~ col" shadow="md violet-900/50 dark:none"
min-w-20 rounded-lg px-2 py-1 h="unset <sm:fit"
class="bg-violet-50/80 <md:bg-violet-500/25 dark:bg-violet-900/80"
>
<div flex="~ row" gap-2>
<div flex-1>
@@ -61,13 +62,14 @@ onTokenLiteral(async () => {
</div>
<div v-if="message.role === 'assistant'" flex mr="12">
<div
flex="~ col" border="2 solid primary-200/50 dark:primary-500/50" shadow="md primary-200/50 dark:none" min-w-20
rounded-lg px-2 py-1 h="unset <sm:fit" bg="<md:primary-500/25"
flex="~ col" shadow="sm primary-200/50 dark:none" min-w-20
rounded-lg px-2 py-1 h="unset <sm:fit"
class="bg-primary-50/80 <md:bg-primary-500/25 dark:bg-primary-900/80"
>
<div>
<span text-xs text="primary-400/90 dark:primary-600/90" font-normal class="inline <sm:hidden">{{ t('stage.chat.message.character-name.airi') }}</span>
</div>
<div v-if="message.content" class="break-words" text="xs primary-400">
<div v-if="message.content" class="break-words" text="primary-700 dark:primary-200">
<div v-for="(slice, sliceIndex) in message.slices" :key="sliceIndex">
<div v-if="slice.type === 'tool-call'">
<div
@@ -88,8 +90,9 @@ onTokenLiteral(async () => {
</div>
<div v-else-if="message.role === 'user'" flex="~ row-reverse" ml="12">
<div
flex="~ col" border="2 solid cyan-200/50 dark:cyan-500/50" shadow="md cyan-200/50 dark:none" px="2"
h="unset <sm:fit" min-w-20 rounded-lg px-2 py-1 bg="<md:cyan-500/25"
flex="~ col" shadow="sm cyan-200/50 dark:none" px="2"
h="unset <sm:fit" min-w-20 rounded-lg px-2 py-1
class="bg-cyan-50/80 <md:bg-cyan-500/25 dark:bg-cyan-900/80"
>
<div>
<span text-xs text="cyan-400/90 dark:cyan-600/90" font-normal class="inline <sm:hidden">{{ t('stage.chat.message.character-name.you') }}</span>
@@ -104,15 +107,16 @@ onTokenLiteral(async () => {
</div>
</div>
</div>
<div v-if="streamingMessage.content" flex mr="12">
<div v-if="sending" flex mr="12">
<div
flex="~ col" border="2 solid primary-200/50 dark:primary-500/50" shadow="md primary-200/50 dark:none" min-w-20
rounded-lg px-2 py-1 h="unset <sm:fit" bg="<md:primary-500/25"
flex="~ col" shadow="sm primary-200/50 dark:none" min-w-20
rounded-lg px-2 py-1 h="unset <sm:fit"
class="bg-primary-50/80 <md:bg-primary-500/25 dark:bg-primary-900/80"
>
<div>
<span text-xs text="primary-400/90 dark:primary-600/90" font-normal class="inline <sm:hidden">{{ t('stage.chat.message.character-name.airi') }}</span>
</div>
<div v-if="streamingMessage.content" class="break-words" text="xs primary-400">
<div v-if="streamingMessage.content" class="break-words" text="primary-700 dark:primary-200">
<div v-for="(slice, sliceIndex) in streamingMessage.slices" :key="sliceIndex">
<div v-if="slice.type === 'tool-call'">
<div
@@ -40,7 +40,7 @@ onTokenLiteral(async () => {
<div v-if="message.role === 'error'" flex mr="12">
<div
flex="~ col"
shadow="md violet-200/20 dark:none"
shadow="sm violet-200/50 dark:none"
min-w-20 rounded-lg px-3 py-2
h="unset <sm:fit"
bg="violet-100 dark:violet-800"
@@ -64,11 +64,11 @@ onTokenLiteral(async () => {
<div v-if="message.role === 'assistant'" flex mr="12">
<div
flex="~ col"
shadow="md primary-200/20 dark:none"
shadow="sm primary-200/50 dark:none"
min-w-20 rounded-lg px-3 py-2
h="unset <sm:fit"
bg="primary-50 dark:primary-800"
backdrop-blur-md
class="bg-primary-50 dark:bg-primary-900"
>
<div>
<span text="primary-400/90 dark:primary-600/90" text-xs font-normal class="inline <sm:hidden">{{ t('stage.chat.message.character-name.airi') }}</span>
@@ -85,7 +85,7 @@ onTokenLiteral(async () => {
<div v-else-if="message.role === 'user'" flex="~">
<div
flex="~ col"
shadow="md cyan-200/20 dark:none"
shadow="sm cyan-200/50 dark:none"
px="2"
h="unset <sm:fit" min-w-20 rounded-lg px-3 py-2
bg="white dark:neutral-800"