计划
一个可折叠的计划组件,用于显示 AI 生成的执行计划,支持流式传输和闪烁动画。
Plan 组件提供了一个灵活的系统来显示 AI 生成的执行计划,具有可折叠的内容。非常适合显示多步骤工作流、任务分解和实施策略,支持流式传输内容和加载状态。
使用 CLI 安装
AI Elements Vue
shadcn-vue CLI
npx ai-elements-vue@latest add plan
npx shadcn-vue@latest add https://registry.ai-elements-vue.com/plan.json
手动安装
将以下代码复制并粘贴到同一文件夹中。
Plan.vue
PlanHeader.vue
PlanTitle.vue
PlanDescription.vue
PlanAction.vue
PlanContent.vue
PlanFooter.vue
PlanTrigger.vue
context.ts
index.ts
<script setup lang="ts">
import type { HTMLAttributes } from 'vue'
import { Card } from '@repo/shadcn-vue/components/ui/card'
import { Collapsible } from '@repo/shadcn-vue/components/ui/collapsible'
import { cn } from '@repo/shadcn-vue/lib/utils'
import { computed } from 'vue'
import { providePlan } from './context'
interface PlanProps {
isStreaming?: boolean
class?: HTMLAttributes['class']
}
const props = withDefaults(
defineProps<PlanProps>(),
{
isStreaming: false,
},
)
providePlan({
isStreaming: computed(() => props.isStreaming),
})
</script>
<template>
<Collapsible as-child data-slot="plan" v-bind="props">
<Card :class="cn('shadow-none', props.class)">
<slot />
</Card>
</Collapsible>
</template>
<script setup lang="ts">
import type { HTMLAttributes } from 'vue'
import { CardHeader } from '@repo/shadcn-vue/components/ui/card'
import { cn } from '@repo/shadcn-vue/lib/utils'
const props = defineProps<{
class?: HTMLAttributes['class']
}>()
</script>
<template>
<CardHeader
:class="cn('flex flex-row items-start justify-between', props.class)"
data-slot="plan-header"
>
<slot />
</CardHeader>
</template>
<script setup lang="ts">
import { CardTitle } from '@repo/shadcn-vue/components/ui/card'
import { Shimmer } from '../shimmer'
import { usePlan } from './context'
const { isStreaming } = usePlan()
</script>
<template>
<CardTitle data-slot="plan-title" v-bind="$attrs">
<Shimmer v-if="isStreaming">
<slot />
</Shimmer>
<slot v-else />
</CardTitle>
</template>
<script setup lang="ts">
import type { HTMLAttributes } from 'vue'
import { CardDescription } from '@repo/shadcn-vue/components/ui/card'
import { cn } from '@repo/shadcn-vue/lib/utils'
import { Shimmer } from '../shimmer'
import { usePlan } from './context'
const props = defineProps<{
class?: HTMLAttributes['class']
}>()
const { isStreaming } = usePlan()
</script>
<template>
<CardDescription
:class="cn('text-balance', props.class)"
data-slot="plan-description"
>
<Shimmer v-if="isStreaming">
<slot />
</Shimmer>
<slot v-else />
</CardDescription>
</template>
<script setup lang="ts">
import { CardAction } from '@repo/shadcn-vue/components/ui/card'
</script>
<template>
<CardAction data-slot="plan-action">
<slot />
</CardAction>
</template>
<script setup lang="ts">
import { CardContent } from '@repo/shadcn-vue/components/ui/card'
import { CollapsibleContent } from '@repo/shadcn-vue/components/ui/collapsible'
</script>
<template>
<CollapsibleContent as-child>
<CardContent data-slot="plan-content">
<slot />
</CardContent>
</CollapsibleContent>
</template>
<script setup lang="ts">
import { CardFooter } from '@repo/shadcn-vue/components/ui/card'
</script>
<template>
<CardFooter data-slot="plan-footer">
<slot />
</CardFooter>
</template>
<script setup lang="ts">
import { Button } from '@repo/shadcn-vue/components/ui/button'
import { CollapsibleTrigger } from '@repo/shadcn-vue/components/ui/collapsible'
import { cn } from '@repo/shadcn-vue/lib/utils'
import { ChevronsUpDownIcon } from 'lucide-vue-next'
const props = defineProps<{
class?: string
}>()
</script>
<template>
<CollapsibleTrigger as-child>
<Button
:class="cn('size-8', props.class)"
data-slot="plan-trigger"
size="icon"
variant="ghost"
>
<ChevronsUpDownIcon class="size-4" />
<span class="sr-only">Toggle plan</span>
</Button>
</CollapsibleTrigger>
</template>
import type { ComputedRef, InjectionKey } from 'vue'
import { inject, provide } from 'vue'
export interface PlanContextValue {
isStreaming: ComputedRef<boolean>
}
export const PlanKey: InjectionKey<PlanContextValue> = Symbol('PlanContext')
export function providePlan(value: PlanContextValue) {
provide(PlanKey, value)
}
export function usePlan() {
const context = inject(PlanKey)
if (!context) {
throw new Error('Plan components must be used within a Plan component')
}
return context
}
export { default as Plan } from './Plan.vue'
export { default as PlanAction } from './PlanAction.vue'
export { default as PlanContent } from './PlanContent.vue'
export { default as PlanDescription } from './PlanDescription.vue'
export { default as PlanFooter } from './PlanFooter.vue'
export { default as PlanHeader } from './PlanHeader.vue'
export { default as PlanTitle } from './PlanTitle.vue'
export { default as PlanTrigger } from './PlanTrigger.vue'
特性
- 具有平滑动画的可折叠内容
- 流式传输支持,带有闪烁加载状态
- 基于 shadcn-vue Card 和 Collapsible 组件构建
- 具有全面类型定义的 TypeScript 支持
- 使用 Tailwind CSS 可自定义样式
- 响应式设计,具有移动友好的交互
- 键盘导航和可访问性支持
- 主题感知,具有自动深色模式支持
- 基于上下文的状态管理,用于流式传输
Props
<Plan />
isStreamingboolean
falsedefaultOpenboolean
falseclassstring
<PlanHeader />
classstring
<PlanDescription />
classstring
<PlanTrigger />
classstring
:::