Skip to content

Commit f684468

Browse files
committed
feat: add image component
1 parent 46d6d70 commit f684468

File tree

13 files changed

+204
-2
lines changed

13 files changed

+204
-2
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@ AI Elements Vue includes the following components:
8989
| `actions` | ✅ 已完成 | Interactive action buttons for AI responses |
9090
| `branch` | ✅ 已完成 | Branch visualization for conversation flows |
9191
| `code-block` | ✅ 已完成 | Syntax-highlighted code display with copy functionality |
92-
| `image` | ❌ 未完成 | AI-generated image display component |
92+
| `image` | ✅ 已完成 | AI-generated image display component |
9393
| `inline-citation` | ❌ 未完成 | Inline source citations |
9494
| `loader` | ❌ 未完成 | Loading states for AI operations |
9595
| `reasoning` | ❌ 未完成 | Display AI reasoning and thought processes |

apps/test/app/examples/image.vue

Lines changed: 18 additions & 0 deletions
Large diffs are not rendered by default.

apps/test/app/examples/index.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
export { default as ActionsHover } from './actions-hover.vue'
2+
export { default as Actions } from './actions.vue'
3+
export { default as Branch } from './branch.vue'
4+
export { default as CodeBlock } from './code-block.vue'
5+
export { default as Conversation } from './conversation.vue'
6+
export { default as Image } from './image.vue'
7+
export { default as MessageMarkdown } from './message-markdown.vue'
8+
export { default as Message } from './message.vue'
9+
export { default as PromptInput } from './prompt-input.vue'
10+
export { default as Response } from './response.vue'

apps/test/app/pages/index.vue

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import Actions from '~/examples/actions.vue'
55
import Branch from '~/examples/branch.vue'
66
import CodeBlock from '~/examples/code-block.vue'
77
import Conversation from '~/examples/conversation.vue'
8+
import Image from '~/examples/image.vue'
89
import MessageMarkdown from '~/examples/message-markdown.vue'
910
import Message from '~/examples/message.vue'
1011
import PromptInput from '~/examples/prompt-input.vue'
@@ -20,6 +21,7 @@ const components = [
2021
{ name: 'Response', Component: Response },
2122
{ name: 'MessageMarkdown', Component: MessageMarkdown },
2223
{ name: 'CodeBlock', Component: CodeBlock },
24+
{ name: 'Image', Component: Image },
2325
]
2426
</script>
2527

apps/www/content/1.overview/1.Introduction.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,4 +30,7 @@ You can install it with:
3030
:::ComponentLoader{label="Branch" componentName="Branch"}
3131
:::
3232

33+
:::ComponentLoader{label="Image" componentName="Image"}
34+
:::
35+
3336
View the [source code](https://github.com/cwandev/ai-elements-vue) for all components on GitHub.
Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
---
2+
title: Image
3+
description:
4+
icon: lucide:image
5+
---
6+
7+
The `Image` component displays AI-generated images from the AI SDK. It accepts a [`Experimental_GeneratedImage`](https://ai-sdk.dev/docs/reference/ai-sdk-core/generate-image#generateimage) object from the AI SDK's `generateImage` function and automatically renders it as an image.
8+
9+
:::ComponentLoader{label="Image" componentName="Image"}
10+
:::
11+
12+
## Install using CLI
13+
14+
:::tabs{variant="card"}
15+
::div{label="ai-elements-vue"}
16+
```sh
17+
npx ai-elements-vue@latest add image
18+
```
19+
::
20+
::div{label="shadcn-vue"}
21+
22+
```sh
23+
npx shadcn-vue@latest add https://registry.ai-elements-vue.com/image.json
24+
```
25+
::
26+
:::
27+
28+
## Install Manually
29+
30+
Copy and paste the following files into the same folder.
31+
32+
:::code-group
33+
```vue [Image.vue]
34+
<script setup lang="ts">
35+
import type { Experimental_GeneratedImage } from 'ai'
36+
import { cn } from '@repo/shadcn-vue/lib/utils'
37+
import { computed, useAttrs } from 'vue'
38+
39+
interface Props extends Experimental_GeneratedImage {
40+
class?: string
41+
alt?: string
42+
}
43+
44+
const props = defineProps<Props>()
45+
const attrs = useAttrs()
46+
47+
const classes = computed(() => cn(
48+
'h-auto max-w-full overflow-hidden rounded-md',
49+
props.class,
50+
))
51+
52+
const src = computed(() => `data:${props.mediaType};base64,${props.base64}`)
53+
</script>
54+
55+
<template>
56+
<img
57+
:alt="props.alt"
58+
:class="classes"
59+
:src="src"
60+
v-bind="attrs"
61+
>
62+
</template>
63+
```
64+
65+
```ts [index.ts]
66+
export { default as Image } from './Image.vue'
67+
```
68+
:::
69+
70+
## Usage
71+
72+
```vue
73+
<script setup lang="ts">
74+
import { Image } from '@/components/ai-elements/image'
75+
76+
const exampleImage = {
77+
base64: 'valid-base64-string',
78+
mediaType: 'image/jpeg',
79+
uint8Array: new Uint8Array([]),
80+
}
81+
</script>
82+
83+
<template>
84+
<Image
85+
v-bind="exampleImage"
86+
alt="Example generated image"
87+
class="h-[150px] aspect-square border"
88+
/>
89+
</template>
90+
```
91+
92+
## Features
93+
94+
- Accepts `Experimental_GeneratedImage` objects directly from the AI SDK
95+
- Automatically creates proper data URLs from base64-encoded image data
96+
- Supports all standard HTML image attributes
97+
- Responsive by default with `max-w-full h-auto` styling
98+
- Customizable with additional CSS classes
99+
- Includes proper TypeScript types for AI SDK compatibility
100+
101+
## Props
102+
103+
### `<Image />`
104+
105+
:::field-group
106+
::field{name="alt" type="string" optional}
107+
Alternative text for the image.
108+
::
109+
110+
::field{name="class" type="string" optional}
111+
Additional CSS classes applied to the `<img>` element.
112+
::
113+
114+
::field{name="[...props]" type="Experimental_GeneratedImage" optional}
115+
The image data to display, as returned by the AI SDK.
116+
::
117+
:::

apps/www/plugins/ai-elements.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import {
33
ActionsHover,
44
Branch,
55
Conversation,
6+
Image,
67
Message,
78
MessageMarkdown,
89
PromptInput,
@@ -26,4 +27,5 @@ export default defineNuxtPlugin((nuxtApp) => {
2627
vueApp.component('PromptInput', PromptInput)
2728
vueApp.component('Conversation', Conversation)
2829
vueApp.component('Response', Response)
30+
vueApp.component('Image', Image)
2931
})
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
<script setup lang="ts">
2+
import type { Experimental_GeneratedImage } from 'ai'
3+
import { cn } from '@repo/shadcn-vue/lib/utils'
4+
import { computed, useAttrs } from 'vue'
5+
6+
interface Props extends Experimental_GeneratedImage {
7+
class?: string
8+
alt?: string
9+
}
10+
11+
const props = defineProps<Props>()
12+
const attrs = useAttrs()
13+
14+
const classes = computed(() => cn(
15+
'h-auto max-w-full overflow-hidden rounded-md',
16+
props.class,
17+
))
18+
19+
const src = computed(() => `data:${props.mediaType};base64,${props.base64}`)
20+
</script>
21+
22+
<template>
23+
<img
24+
:alt="props.alt"
25+
:class="classes"
26+
:src="src"
27+
v-bind="attrs"
28+
>
29+
</template>
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export { default as Image } from './Image.vue'

packages/elements/src/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ export * from './actions'
22
export * from './branch'
33
export * from './code-block'
44
export * from './conversation'
5+
export * from './image'
56
export * from './message'
67
export * from './prompt-input'
78
export * from './response'

0 commit comments

Comments
 (0)