Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ AI Elements Vue includes the following components:
| `conversation` | ✅ 已完成 | Container for chat conversations |
| `response` | ✅ 已完成 | Formatted AI response display |
| `prompt-input` | ✅ 已完成 | Advanced input component with model selection |
| `actions` | ❌ 未完成 | Interactive action buttons for AI responses |
| `actions` | ✅ 已完成 | Interactive action buttons for AI responses |
| `branch` | ❌ 未完成 | Branch visualization for conversation flows |
| `code-block` | ❌ 未完成 | Syntax-highlighted code display with copy functionality |
| `image` | ❌ 未完成 | AI-generated image display component |
Expand Down
49 changes: 49 additions & 0 deletions apps/test/app/examples/actions-hover.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
<script setup lang="ts">
import { Action, Actions } from '@repo/elements/actions'
import { Message, MessageContent } from '@repo/elements/message'
import { Copy, Heart, RefreshCcw, Share, ThumbsDown, ThumbsUp } from 'lucide-vue-next'
import { ref } from 'vue'

const liked = ref(false)
const disliked = ref(false)
const favorited = ref(false)

const responseContent = `This is a response from an assistant.

Try hovering over this message to see the actions appear!`

function handleRetry() {
// eslint-disable-next-line no-console
console.log('Retrying request...')
}

function handleCopy(content?: string) {
// eslint-disable-next-line no-console
console.log('Copied:', content)
}

function handleShare(content?: string) {
// eslint-disable-next-line no-console
console.log('Sharing:', content)
}

const actions = [
{ icon: RefreshCcw, label: 'Retry', onClick: handleRetry },
{ icon: ThumbsUp, label: 'Like', onClick: () => (liked.value = !liked.value) },
{ icon: ThumbsDown, label: 'Dislike', onClick: () => (disliked.value = !disliked.value) },
{ icon: Copy, label: 'Copy', onClick: () => handleCopy(responseContent) },
{ icon: Share, label: 'Share', onClick: () => handleShare(responseContent) },
{ icon: Heart, label: 'Favorite', onClick: () => (favorited.value = !favorited.value) },
]
</script>

<template>
<Message class="group flex flex-col items-start gap-2" from="assistant">
<MessageContent>{{ responseContent }}</MessageContent>
<Actions class="mt-2 opacity-0 group-hover:opacity-100">
<Action v-for="action in actions" :key="action.label" :label="action.label" @click="action.onClick">
<component :is="action.icon" class="size-3" />
</Action>
</Actions>
</Message>
</template>
69 changes: 69 additions & 0 deletions apps/test/app/examples/actions.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
<script setup lang="ts">
import { Action, Actions } from '@repo/elements/actions'
import { Conversation, ConversationContent } from '@repo/elements/conversation'
import { Message, MessageContent } from '@repo/elements/message'
import { Copy, RefreshCcw, Share, ThumbsDown, ThumbsUp } from 'lucide-vue-next'
import { nanoid } from 'nanoid'
import { ref } from 'vue'

interface MsgItem {
key: string
from: 'user' | 'assistant'
content: string
avatar: string
name: string
}

const messages: MsgItem[] = [
{
key: nanoid(),
from: 'user',
content: 'Hello, how are you?',
avatar: 'https://github.com/haydenbleasel.png',
name: 'Hayden Bleasel',
},
{
key: nanoid(),
from: 'assistant',
content: 'I am fine, thank you!',
avatar: 'https://github.com/openai.png',
name: 'OpenAI',
},
]

const liked = ref(false)
const disliked = ref(false)

function handleRetry() {}
function handleCopy() {}
function handleShare() {}

const actions = [
{ icon: RefreshCcw, label: 'Retry', onClick: handleRetry },
{ icon: ThumbsUp, label: 'Like', onClick: () => (liked.value = !liked.value) },
{ icon: ThumbsDown, label: 'Dislike', onClick: () => (disliked.value = !disliked.value) },
{ icon: Copy, label: 'Copy', onClick: () => handleCopy() },
{ icon: Share, label: 'Share', onClick: () => handleShare() },
]
</script>

<template>
<Conversation class="relative w-full">
<ConversationContent>
<Message
v-for="message in messages"
:key="message.key"
:from="message.from"
class="flex flex-col gap-2"
:class="message.from === 'assistant' ? 'items-start' : 'items-end'"
>
<MessageContent>{{ message.content }}</MessageContent>
<Actions v-if="message.from === 'assistant'" class="mt-2">
<Action v-for="action in actions" :key="action.label" :label="action.label" @click="action.onClick">
<component :is="action.icon" class="size-4" />
</Action>
</Actions>
</Message>
</ConversationContent>
</Conversation>
</template>
4 changes: 4 additions & 0 deletions apps/test/app/pages/index.vue
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
<script setup lang="ts">
import { Card, CardContent, CardHeader, CardTitle } from '@repo/shadcn-vue/components/ui/card'
import ActionsHover from '~/examples/actions-hover.vue'
import Actions from '~/examples/actions.vue'
import Conversation from '~/examples/conversation.vue'
import MessageMarkdown from '~/examples/message-markdown.vue'
import Message from '~/examples/message.vue'
Expand All @@ -8,6 +10,8 @@ import Response from '~/examples/response.vue'

const components = [
{ name: 'Message', Component: Message },
{ name: 'Actions', Component: Actions },
{ name: 'ActionsHover', Component: ActionsHover },
{ name: 'PromptInput', Component: PromptInput },
{ name: 'Conversation', Component: Conversation },
{ name: 'Response', Component: Response },
Expand Down
3 changes: 3 additions & 0 deletions apps/www/content/1.overview/1.Introduction.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,4 +24,7 @@ You can install it with:
:::ComponentLoader{label="Response" componentName="Response"}
:::

:::ComponentLoader{label="Actions" componentName="Actions"}
:::

View the [source code](https://github.com/cwandev/ai-elements-vue) for all components on GitHub.
Loading