ChatMessage专业版

GitHub
显示带有图标、头像和操作的聊天消息。

用法

ChatMessage 组件渲染一个用于<article>元素,显示userassistant聊天消息。

你好!请告诉我更多关于使用 Nuxt UI Pro 构建 AI 聊天机器人的信息。
使用ChatMessages组件来显示聊天消息列表。

内容

使用content prop 来显示消息内容。

你好!请告诉我更多关于使用 Nuxt UI Pro 构建 AI 聊天机器人的信息。
<template>
  <UChatMessage content="Hello! Tell me more about building AI chatbots with Nuxt UI Pro." />
</template>

方向

使用side prop 来显示消息在左侧还是右侧。

你好!请告诉我更多关于使用 Nuxt UI Pro 构建 AI 聊天机器人的信息。
<template>
  <UChatMessage
    side="right"
    content="Hello! Tell me more about building AI chatbots with Nuxt UI Pro."
  />
</template>
当使用ChatMessages组件时,assistant消息的side prop 设置为leftuser消息的right

变体

使用variant prop 来更改消息的样式。

你好!请告诉我更多关于使用 Nuxt UI Pro 构建 AI 聊天机器人的信息。
<template>
  <UChatMessage
    variant="soft"
    content="Hello! Tell me more about building AI chatbots with Nuxt UI Pro."
  />
</template>
当使用ChatMessages组件时,assistant消息的variant prop 设置为nakeduser消息的soft

Icon

使用icon prop 来在消息旁边显示一个Icon组件。

你好!请告诉我更多关于使用 Nuxt UI Pro 构建 AI 聊天机器人的信息。
<template>
  <UChatMessage
    icon="i-lucide-user"
    variant="soft"
    side="right"
    content="Hello! Tell me more about building AI chatbots with Nuxt UI Pro."
  />
</template>

Avatar

使用avatar prop 来在消息旁边显示一个Avatar组件。

你好!请告诉我更多关于使用 Nuxt UI Pro 构建 AI 聊天机器人的信息。
<template>
  <UChatMessage
    :avatar="{
      src: 'https://github.com/benjamincanac.png'
    }"
    variant="soft"
    side="right"
    content="Hello! Tell me more about building AI chatbots with Nuxt UI Pro."
  />
</template>

您也可以使用avatar.icon prop 将图标显示为头像。

Nuxt UI Pro 提供了多种用于构建 AI 聊天机器人的功能,包括 ChatMessage、ChatMessages 和 ChatPrompt 组件。最佳实践包括使用 Vercel AI SDK 的 useChat composable、通过变体实现适当的消息样式,以及利用内置的操作进行消息交互。这些组件完全可定制,并支持主题和响应式设计。
<template>
  <UChatMessage
    :avatar="{
      icon: 'i-lucide-bot'
    }"
    content="Nuxt UI Pro offers several features for building AI chatbots including the ChatMessage, ChatMessages, and ChatPrompt components. Best practices include using the useChat composable from Vercel AI SDK, implementing proper message styling with variants, and utilizing the built-in actions for message interactions. The components are fully customizable with theming support and responsive design."
  />
</template>

操作

使用actions prop 来在消息下方显示操作,这些操作会在鼠标悬停在消息上时显示。

Nuxt UI Pro 提供了多种用于构建 AI 聊天机器人的功能,包括 ChatMessage、ChatMessages 和 ChatPrompt 组件。最佳实践包括使用 Vercel AI SDK 的 useChat composable、通过变体实现适当的消息样式,以及利用内置的操作进行消息交互。这些组件完全可定制,并支持主题和响应式设计。
<script setup lang="ts">
const actions = ref([
  {
    label: 'Copy to clipboard',
    icon: 'i-lucide-copy'
  }
])
</script>

<template>
  <UChatMessage
    :actions="actions"
    content="Nuxt UI Pro offers several features for building AI chatbots including the ChatMessage, ChatMessages, and ChatPrompt components. Best practices include using the useChat composable from Vercel AI SDK, implementing proper message styling with variants, and utilizing the built-in actions for message interactions. The components are fully customizable with theming support and responsive design."
  />
</template>

API

属性

属性默认值类型
as

'article'

任何

此组件应渲染为的元素或组件。

id

字符串

消息的唯一标识符。

内容

字符串

消息的文本内容。尽可能使用 parts。

role

"data" | "user" | "system" | "assistant"

“data”角色已弃用。

图标

字符串

avatar

AvatarProps & { [key: string]: any; }

变体

'naked'

"solid" | "outline" | "soft" | "subtle" | "naked"

方向

'left'

"right" | "left"

actions

(Omit<ButtonProps, "onClick> & { onClick?: ((e: MouseEvent, message: Message) => void) | undefined; })[]

在消息下方显示操作列表。label将用于工具提示中。{ size: 'xs', color: 'neutral', variant: 'ghost' }

紧凑

false

布尔值

以紧凑样式渲染消息。在UChatPalette内部使用时会自动完成。

createdAt

日期

消息的时间戳。

reasoning

字符串

消息的推理。

experimental_attachments

Attachment[]

随消息发送的附加附件。

数据

null | string | number | false | true | { [value: string]: JSONValue; } | JSONValue[]

用于数据消息。

annotations

JSONValue[]

通过 StreamData 在服务器上添加的附加消息特定信息

toolInvocations

ToolInvocation[]

助手作为此消息的一部分进行的工具调用(可以是工具调用或工具结果,具体取决于调用是否完成)。

parts

(TextUIPart | ReasoningUIPart | ToolInvocationUIPart | SourceUIPart | FileUIPart | StepStartUIPart)[]

消息的组成部分。用于在 UI 中渲染消息。

助手消息可以包含文本、推理和工具调用部分。用户消息可以包含文本部分。

UI

{ root?: ClassNameValue; container?: ClassNameValue; leading?: ClassNameValue; leadingIcon?: ClassNameValue; leadingAvatar?: ClassNameValue; leadingAvatarSize?: ClassNameValue; content?: ClassNameValue; actions?: ClassNameValue; }

插槽

插槽类型
前置

{ avatar: (AvatarProps & { [key: string]: any; }) | undefined; }

内容

Pick<ChatMessageProps, "content" | "reasoning" | "experimental_attachments" | "annotations" | "toolInvocations" | "parts">

actions

{ actions: (Omit<ButtonProps, "onClick> & { onClick?: ((e: MouseEvent, message: Message) => void) | undefined; })[] | undefined; }

主题

app.config.ts
export default defineAppConfig({
  uiPro: {
    chatMessage: {
      slots: {
        root: 'group/message relative w-full',
        container: 'relative flex items-start group-data-[role=user]/message:max-w-[75%]',
        leading: 'inline-flex items-center justify-center min-h-6',
        leadingIcon: 'shrink-0',
        leadingAvatar: 'shrink-0',
        leadingAvatarSize: '',
        content: 'relative text-pretty min-w-0',
        actions: [
          'opacity-0 group-hover/message:opacity-100 absolute bottom-0 flex items-center',
          'transition-opacity'
        ]
      },
      variants: {
        variant: {
          solid: {
            content: 'bg-inverted text-inverted'
          },
          outline: {
            content: 'bg-default ring ring-default'
          },
          soft: {
            content: 'bg-elevated/50'
          },
          subtle: {
            content: 'bg-elevated/50 ring ring-default'
          },
          naked: {
            content: ''
          }
        },
        side: {
          left: {
            container: 'rtl:justify-end'
          },
          right: {
            container: 'ltr:justify-end ms-auto'
          }
        },
        leading: {
          true: ''
        },
        actions: {
          true: ''
        },
        compact: {
          true: {
            root: 'scroll-mt-3',
            container: 'gap-1.5 pb-3',
            leadingIcon: 'size-5',
            leadingAvatarSize: '2xs'
          },
          false: {
            root: 'scroll-mt-4 sm:scroll-mt-6',
            container: 'gap-3 pb-8',
            leadingIcon: 'size-8',
            leadingAvatarSize: 'md'
          }
        }
      },
      compoundVariants: [
        {
          compact: true,
          actions: true,
          class: {
            container: 'pb-8'
          }
        },
        {
          leading: true,
          compact: false,
          side: 'left',
          class: {
            actions: 'left-11'
          }
        },
        {
          leading: true,
          compact: true,
          side: 'left',
          class: {
            actions: 'left-6.5'
          }
        },
        {
          variant: [
            'solid',
            'outline',
            'soft',
            'subtle'
          ],
          compact: false,
          class: {
            content: 'px-4 py-3 rounded-lg min-h-12',
            leading: 'mt-2'
          }
        },
        {
          variant: [
            'solid',
            'outline',
            'soft',
            'subtle'
          ],
          compact: true,
          class: {
            content: 'px-2 py-1 rounded-lg min-h-8',
            leading: 'mt-1'
          }
        }
      ],
      defaultVariants: {
        variant: 'naked'
      }
    }
  }
})
vite.config.ts
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import ui from '@nuxt/ui/vite'

export default defineConfig({
  plugins: [
    vue(),
    ui({
      uiPro: {
        chatMessage: {
          slots: {
            root: 'group/message relative w-full',
            container: 'relative flex items-start group-data-[role=user]/message:max-w-[75%]',
            leading: 'inline-flex items-center justify-center min-h-6',
            leadingIcon: 'shrink-0',
            leadingAvatar: 'shrink-0',
            leadingAvatarSize: '',
            content: 'relative text-pretty min-w-0',
            actions: [
              'opacity-0 group-hover/message:opacity-100 absolute bottom-0 flex items-center',
              'transition-opacity'
            ]
          },
          variants: {
            variant: {
              solid: {
                content: 'bg-inverted text-inverted'
              },
              outline: {
                content: 'bg-default ring ring-default'
              },
              soft: {
                content: 'bg-elevated/50'
              },
              subtle: {
                content: 'bg-elevated/50 ring ring-default'
              },
              naked: {
                content: ''
              }
            },
            side: {
              left: {
                container: 'rtl:justify-end'
              },
              right: {
                container: 'ltr:justify-end ms-auto'
              }
            },
            leading: {
              true: ''
            },
            actions: {
              true: ''
            },
            compact: {
              true: {
                root: 'scroll-mt-3',
                container: 'gap-1.5 pb-3',
                leadingIcon: 'size-5',
                leadingAvatarSize: '2xs'
              },
              false: {
                root: 'scroll-mt-4 sm:scroll-mt-6',
                container: 'gap-3 pb-8',
                leadingIcon: 'size-8',
                leadingAvatarSize: 'md'
              }
            }
          },
          compoundVariants: [
            {
              compact: true,
              actions: true,
              class: {
                container: 'pb-8'
              }
            },
            {
              leading: true,
              compact: false,
              side: 'left',
              class: {
                actions: 'left-11'
              }
            },
            {
              leading: true,
              compact: true,
              side: 'left',
              class: {
                actions: 'left-6.5'
              }
            },
            {
              variant: [
                'solid',
                'outline',
                'soft',
                'subtle'
              ],
              compact: false,
              class: {
                content: 'px-4 py-3 rounded-lg min-h-12',
                leading: 'mt-2'
              }
            },
            {
              variant: [
                'solid',
                'outline',
                'soft',
                'subtle'
              ],
              compact: true,
              class: {
                content: 'px-2 py-1 rounded-lg min-h-8',
                leading: 'mt-1'
              }
            }
          ],
          defaultVariants: {
            variant: 'naked'
          }
        }
      }
    })
  ]
})
vite.config.ts
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import uiPro from '@nuxt/ui-pro/vite'

export default defineConfig({
  plugins: [
    vue(),
    uiPro({
      uiPro: {
        chatMessage: {
          slots: {
            root: 'group/message relative w-full',
            container: 'relative flex items-start group-data-[role=user]/message:max-w-[75%]',
            leading: 'inline-flex items-center justify-center min-h-6',
            leadingIcon: 'shrink-0',
            leadingAvatar: 'shrink-0',
            leadingAvatarSize: '',
            content: 'relative text-pretty min-w-0',
            actions: [
              'opacity-0 group-hover/message:opacity-100 absolute bottom-0 flex items-center',
              'transition-opacity'
            ]
          },
          variants: {
            variant: {
              solid: {
                content: 'bg-inverted text-inverted'
              },
              outline: {
                content: 'bg-default ring ring-default'
              },
              soft: {
                content: 'bg-elevated/50'
              },
              subtle: {
                content: 'bg-elevated/50 ring ring-default'
              },
              naked: {
                content: ''
              }
            },
            side: {
              left: {
                container: 'rtl:justify-end'
              },
              right: {
                container: 'ltr:justify-end ms-auto'
              }
            },
            leading: {
              true: ''
            },
            actions: {
              true: ''
            },
            compact: {
              true: {
                root: 'scroll-mt-3',
                container: 'gap-1.5 pb-3',
                leadingIcon: 'size-5',
                leadingAvatarSize: '2xs'
              },
              false: {
                root: 'scroll-mt-4 sm:scroll-mt-6',
                container: 'gap-3 pb-8',
                leadingIcon: 'size-8',
                leadingAvatarSize: 'md'
              }
            }
          },
          compoundVariants: [
            {
              compact: true,
              actions: true,
              class: {
                container: 'pb-8'
              }
            },
            {
              leading: true,
              compact: false,
              side: 'left',
              class: {
                actions: 'left-11'
              }
            },
            {
              leading: true,
              compact: true,
              side: 'left',
              class: {
                actions: 'left-6.5'
              }
            },
            {
              variant: [
                'solid',
                'outline',
                'soft',
                'subtle'
              ],
              compact: false,
              class: {
                content: 'px-4 py-3 rounded-lg min-h-12',
                leading: 'mt-2'
              }
            },
            {
              variant: [
                'solid',
                'outline',
                'soft',
                'subtle'
              ],
              compact: true,
              class: {
                content: 'px-2 py-1 rounded-lg min-h-8',
                leading: 'mt-1'
              }
            }
          ],
          defaultVariants: {
            variant: 'naked'
          }
        }
      }
    })
  ]
})