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 @@ -88,7 +88,7 @@ AI Elements Vue includes the following components:
| `prompt-input` | ✅ 已完成 | Advanced input component with model selection |
| `actions` | ✅ 已完成 | Interactive action buttons for AI responses |
| `branch` | ✅ 已完成 | Branch visualization for conversation flows |
| `code-block` | ❌ 未完成 | Syntax-highlighted code display with copy functionality |
| `code-block` | ✅ 已完成 | Syntax-highlighted code display with copy functionality |
| `image` | ❌ 未完成 | AI-generated image display component |
| `inline-citation` | ❌ 未完成 | Inline source citations |
| `loader` | ❌ 未完成 | Loading states for AI operations |
Expand Down
2 changes: 1 addition & 1 deletion apps/registry/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
"dev": "nitro dev --port 3001"
},
"devDependencies": {
"@vue/compiler-sfc": "^3.5.21",
"@vue/compiler-sfc": "^3.5.22",
"h3": "^1.15.4",
"nitropack": "^2.12.6",
"ts-morph": "^27.0.0"
Expand Down
22 changes: 22 additions & 0 deletions apps/test/app/examples/code-block.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<script setup lang="ts">
import { CodeBlock } from '@repo/elements/code-block'

const code = `<template>
<div>
<h1>Hello, {{ name }}!</h1>
<p>This is an example Vue component.</p>
</div>
</template>

<script setup lang="ts">
interface Props {
name: string
}

defineProps<Props>()
<\/script>`
</script>

<template>
<CodeBlock :code="code" lang="vue" />
</template>
2 changes: 2 additions & 0 deletions apps/test/app/pages/index.vue
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { Card, CardContent, CardHeader, CardTitle } from '@repo/shadcn-vue/compo
import ActionsHover from '~/examples/actions-hover.vue'
import Actions from '~/examples/actions.vue'
import Branch from '~/examples/branch.vue'
import CodeBlock from '~/examples/code-block.vue'
import Conversation from '~/examples/conversation.vue'
import MessageMarkdown from '~/examples/message-markdown.vue'
import Message from '~/examples/message.vue'
Expand All @@ -18,6 +19,7 @@ const components = [
{ name: 'Conversation', Component: Conversation },
{ name: 'Response', Component: Response },
{ name: 'MessageMarkdown', Component: MessageMarkdown },
{ name: 'CodeBlock', Component: CodeBlock },
]
</script>

Expand Down
12 changes: 6 additions & 6 deletions apps/test/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,22 +13,22 @@
"dependencies": {
"@repo/elements": "workspace:*",
"@repo/shadcn-vue": "workspace:*",
"@tailwindcss/vite": "^4.1.13",
"@tailwindcss/vite": "^4.1.14",
"@vueuse/core": "^13.9.0",
"ai": "^5.0.51",
"ai": "^5.0.60",
"class-variance-authority": "^0.7.1",
"clsx": "^2.1.1",
"lucide-vue-next": "^0.544.0",
"nanoid": "^5.1.6",
"nuxt": "^4.1.2",
"shadcn-nuxt": "2.2.0",
"shadcn-nuxt": "2.3.1",
"tailwind-merge": "^3.3.1",
"tailwindcss": "^4.1.13",
"tailwindcss": "^4.1.14",
"tw-animate-css": "^1.4.0",
"vue": "^3.5.21",
"vue": "^3.5.22",
"vue-router": "^4.5.1"
},
"devDependencies": {
"typescript": "^5.9.2"
"typescript": "^5.9.3"
}
}
4 changes: 2 additions & 2 deletions apps/www/content/2.components/6.branch.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ icon: lucide:git-branch

The `Branch` component manages multiple versions of AI messages, allowing users to navigate between different response branches. It provides a clean, modern interface with customizable themes and keyboard-accessible navigation buttons.

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

## Install using CLI

Expand Down
167 changes: 167 additions & 0 deletions apps/www/content/2.components/7.code-block.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,167 @@
---
title: Code Block
description:
icon: lucide:code
---

The `CodeBlock` component provides syntax highlighting and copy to clipboard functionality for code blocks. It uses Shiki for syntax highlighting and includes automatic light/dark theme switching.

## Install using CLI

:::tabs{variant="card"}
::div{label="ai-elements-vue"}
```sh
npx ai-elements-vue@latest add code-block
```
::
::div{label="shadcn-vue"}

```sh
npx shadcn-vue@latest add https://registry.ai-elements-vue.com/code-block.json
```
::
:::

## Install Manually

Copy and paste the following files into the same folder.

:::code-group
```vue [CodeBlock.vue]
<script setup lang="ts">
import type { BuiltinTheme, BundledLanguage } from 'shiki'
import { transformerCopyButton } from '@selemondev/shiki-transformer-copy-button'
import CodeBlock from 'shiki-block-vue'

interface Props {
code: string
lang: BundledLanguage
}

const props = withDefaults(defineProps<Props>(), {})

const theme: { light: BuiltinTheme, dark: BuiltinTheme } = {
light: 'vitesse-light',
dark: 'vitesse-dark',
}
</script>

<template>
<CodeBlock
:lang="props.lang"
:code="props.code"
:theme="theme"
class="overflow-hidden"
:transformers="[
transformerCopyButton({
duration: 3000,
display: 'ready',
successIcon: `data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='none' stroke='rgba(128,128,128,1)' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' viewBox='0 0 24 24'%3E%3Crect width='8' height='4' x='8' y='2' rx='1' ry='1'/%3E%3Cpath d='M16 4h2a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2V6a2 2 0 0 1 2-2h2'/%3E%3Cpath d='m9 14 2 2 4-4'/%3E%3C/svg%3E`,
copyIcon: `data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='none' stroke='rgba(128,128,128,1)' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' viewBox='0 0 24 24'%3E%3Crect width='8' height='4' x='8' y='2' rx='1' ry='1'/%3E%3Cpath d='M16 4h2a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2V6a2 2 0 0 1 2-2h2'/%3E%3Cpath d='m9 14 2 2 4-4'/%3E%3C/svg%3E`,
}),
]"
/>
</template>

<style scoped>
/* Dark Mode */
@media (prefers-color-scheme: dark) {
:deep(.shiki),
:deep(.shiki span) {
color: var(--shiki-dark) !important;
background-color: var(--shiki-dark-bg) !important;
/* Optional, if you also want font styles */
font-style: var(--shiki-dark-font-style) !important;
font-weight: var(--shiki-dark-font-weight) !important;
text-decoration: var(--shiki-dark-text-decoration) !important;
}
}

html.dark :deep(.shiki),
html.dark :deep(.shiki span) {
color: var(--shiki-dark) !important;
background-color: var(--shiki-dark-bg) !important;
font-style: var(--shiki-dark-font-style) !important;
font-weight: var(--shiki-dark-font-weight) !important;
text-decoration: var(--shiki-dark-text-decoration) !important;
}

:deep(.shiki--code--block) {
width: 100%;
}

:deep(pre) {
z-index: 1;
padding: 24px;
border-radius: 10px;
overflow-x: auto;
-ms-overflow-style: none;
scrollbar-width: none;
position: relative;
background-color: #F9F9F9 !important;
}

:deep(code) {
display: block;
line-height: 1.7;
font-size: 15px;
}
</style>
```

```ts [index.ts]
export { default as CodeBlock } from './CodeBlock.vue'
```
:::

## Usage

```vue
<script setup lang="ts">
import { CodeBlock } from '@/components/ai-elements/code-block'

const code = `<template>
<div>
<h1>Hello, {{ name }}!</h1>
<p>This is an example Vue component.</p>
</div>
</template>

<script setup lang="ts">
interface Props {
name: string
}

defineProps<Props>()
<\/script>`
</script>

<template>
<CodeBlock :code="code" lang="vue" />
</template>
```

## Features

- Syntax highlighting with Shiki
- Copy to clipboard functionality
- Automatic light/dark theme switching
- Support for all Shiki bundled languages
- Customizable themes (vitesse-light/vitesse-dark)
- Responsive design with horizontal scrolling
- Clean, modern styling
- Accessible design

## Props

### `<CodeBlock />`

:::field-group
::field{name="code" type="string" required}
The code content to display.
::

::field{name="lang" type="BundledLanguage" required}
The programming language for syntax highlighting. Supports all Shiki bundled languages.
::
:::
1 change: 0 additions & 1 deletion apps/www/nuxt.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ export default defineNuxtConfig({

components: [
{ path: '~/components' },
{ path: '../../packages/examples/src', pathPrefix: false },
],

i18n: {
Expand Down
6 changes: 3 additions & 3 deletions apps/www/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,13 @@
"@repo/examples": "workspace:*",
"nuxt": "3.18.0",
"shadcn-docs-nuxt": "^1.1.2",
"tailwindcss": "^4.1.13",
"vue": "^3.5.21",
"tailwindcss": "^4.1.14",
"vue": "^3.5.22",
"vue-router": "^4.5.1"
},
"devDependencies": {
"@iconify-json/logos": "^1.2.9",
"@iconify-json/simple-icons": "^1.2.53",
"@iconify-json/simple-icons": "^1.2.54",
"tailwindcss-animate": "^1.0.7"
}
}
14 changes: 7 additions & 7 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"name": "ai-elements-vue",
"version": "0.3.0",
"private": true,
"packageManager": "pnpm@10.17.1",
"packageManager": "pnpm@10.18.0",
"engines": {
"node": ">=20.19.0"
},
Expand All @@ -22,14 +22,14 @@
},
"devDependencies": {
"@antfu/eslint-config": "^5.4.1",
"@commitlint/cli": "^19.8.1",
"@commitlint/config-conventional": "^19.8.1",
"bumpp": "^10.2.3",
"eslint": "^9.36.0",
"lint-staged": "^16.2.0",
"@commitlint/cli": "^20.1.0",
"@commitlint/config-conventional": "^20.0.0",
"bumpp": "^10.3.1",
"eslint": "^9.37.0",
"lint-staged": "^16.2.3",
"simple-git-hooks": "^2.13.1",
"turbo": "^2.5.8",
"typescript": "^5.9.2"
"typescript": "^5.9.3"
},
"pnpm": {
"allowedDeprecatedVersions": {
Expand Down
9 changes: 6 additions & 3 deletions packages/elements/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,16 @@
},
"dependencies": {
"@repo/shadcn-vue": "workspace:*",
"ai": "^5.0.51",
"@selemondev/shiki-transformer-copy-button": "^0.0.2",
"ai": "^5.0.60",
"lucide-vue-next": "^0.544.0",
"shiki-block-vue": "^1.0.5",
"streamdown-vue": "^1.0.21",
"vue": "^3.5.21",
"vue": "^3.5.22",
"vue-stick-to-bottom": "^0.1.0"
},
"devDependencies": {
"typescript": "^5.9.2"
"shiki": "^3.13.0",
"typescript": "^5.9.3"
}
}
Loading