unnamed-ui
按钮

Quick Action

Composed quick action panel for suggestions and next steps

你好,我今天能帮你什么?

选择一个快速操作开始对话

"use client";

import {
  QuickActionButton,
  QuickActionGroup,
  QuickActionIcon,
} from "@/components/composed/quick-action/quick-action";
import {
  Sparkles,
  FileText,
  Lightbulb,
  BookOpen,
  Code,
  MessageSquare,
} from "lucide-react";

export function QuickActionDemo() {
  return (
    <div className="flex flex-col gap-6 w-full">
      <div className="text-center">
        <h3 className="text-lg font-medium text-[var(--Text-text-primary)] mb-2">
          你好,我今天能帮你什么?
        </h3>
        <p className="text-sm text-[var(--Text-text-secondary)]">
          选择一个快速操作开始对话
        </p>
      </div>

      <QuickActionGroup>
        <QuickActionButton onClick={() => alert("总结内容")}>
          <QuickActionIcon>
            <Sparkles className="size-4" />
          </QuickActionIcon>
          <span>帮我总结一下这段内容</span>
        </QuickActionButton>
        <QuickActionButton onClick={() => alert("学习计划")}>
          <QuickActionIcon>
            <FileText className="size-4" />
          </QuickActionIcon>
          <span>给我列一个学习计划</span>
        </QuickActionButton>
        <QuickActionButton onClick={() => alert("解释概念")}>
          <QuickActionIcon>
            <Lightbulb className="size-4" />
          </QuickActionIcon>
          <span>解释一下这个概念</span>
        </QuickActionButton>
        <QuickActionButton onClick={() => alert("推荐资源")}>
          <QuickActionIcon>
            <BookOpen className="size-4" />
          </QuickActionIcon>
          <span>推荐一些学习资源</span>
        </QuickActionButton>
        <QuickActionButton onClick={() => alert("代码审查")}>
          <QuickActionIcon>
            <Code className="size-4" />
          </QuickActionIcon>
          <span>帮我审查这段代码</span>
        </QuickActionButton>
        <QuickActionButton onClick={() => alert("翻译文本")}>
          <QuickActionIcon>
            <MessageSquare className="size-4" />
          </QuickActionIcon>
          <span>翻译这段文本</span>
        </QuickActionButton>
      </QuickActionGroup>
    </div>
  );
}

Quick Action 组件用于展示快速操作建议,支持标题、描述和图标,适用于聊天界面的空状态、对话引导、快捷操作等场景。

概述

  • 标题和描述:可选的标题和描述文本,提供上下文说明
  • 图标支持:每个操作按钮可配置独立图标
  • 数据驱动:通过 items 数组快速生成操作列表
  • 灵活组合:QuickActionGroup、Button、Icon、Panel 可独立或组合使用
  • 响应式布局:自动适应容器宽度,按钮自动换行
  • 交互友好:清晰的悬停和点击状态反馈

快速开始

import { QuickActionPanel } from "@/registry/wuhan/composed/quick-action";
import { MessageSquare, FileText, Code } from "lucide-react";

export function Example() {
  const actions = [
    { text: "开始新对话", icon: MessageSquare },
    { text: "查看文档", icon: FileText },
    { text: "示例代码", icon: Code },
  ];
  
  return (
    <QuickActionPanel
      title="快速开始"
      description="选择一个操作开始使用"
      items={actions}
      onActionClick={(text) => console.log(text)}
    />
  );
}

特性

  • 标题描述:可选的标题和描述,为操作提供上下文
  • 图标配置:每个操作可配置不同的图标组件
  • 数据驱动:通过数组数据快速生成操作按钮
  • 独立组件:QuickActionButton 可单独使用
  • 灵活布局:按钮自动换行,适应不同屏幕尺寸
  • 禁用状态:支持禁用单个或全部操作按钮

安装

pnpm dlx shadcn@latest add http://localhost:3000/r/wuhan/quick-action.json

代码演示

基本

基础的快速操作按钮组,展示纯文本操作。

"use client";

import {
  QuickActionButton,
  QuickActionGroup,
} from "@/components/composed/quick-action/quick-action";

export function QuickActionDefault() {
  return (
    <QuickActionGroup>
      <QuickActionButton onClick={() => alert("帮我总结一下这段内容")}>
        帮我总结一下这段内容
      </QuickActionButton>
      <QuickActionButton onClick={() => alert("给我列一个学习计划")}>
        给我列一个学习计划
      </QuickActionButton>
      <QuickActionButton onClick={() => alert("解释一下这个概念")}>
        解释一下这个概念
      </QuickActionButton>
    </QuickActionGroup>
  );
}

带图标

带图标的快速操作按钮,让操作更加直观和吸引人。

"use client";

import {
  QuickActionButton,
  QuickActionGroup,
  QuickActionIcon,
} from "@/components/composed/quick-action/quick-action";
import { Sparkles, FileText, Lightbulb, BookOpen } from "lucide-react";

export function QuickActionWithIcons() {
  return (
    <QuickActionGroup>
      <QuickActionButton onClick={() => alert("总结内容")}>
        <QuickActionIcon>
          <Sparkles className="size-4" />
        </QuickActionIcon>
        <span>帮我总结一下这段内容</span>
      </QuickActionButton>
      <QuickActionButton onClick={() => alert("学习计划")}>
        <QuickActionIcon>
          <FileText className="size-4" />
        </QuickActionIcon>
        <span>给我列一个学习计划</span>
      </QuickActionButton>
      <QuickActionButton onClick={() => alert("解释概念")}>
        <QuickActionIcon>
          <Lightbulb className="size-4" />
        </QuickActionIcon>
        <span>解释一下这个概念</span>
      </QuickActionButton>
      <QuickActionButton onClick={() => alert("推荐资源")}>
        <QuickActionIcon>
          <BookOpen className="size-4" />
        </QuickActionIcon>
        <span>推荐一些学习资源</span>
      </QuickActionButton>
    </QuickActionGroup>
  );
}

单个按钮

单独使用快速操作按钮,无需按钮组包裹。

"use client";

import {
  QuickActionButton,
  QuickActionIcon,
} from "@/components/composed/quick-action/quick-action";
import { Sparkles } from "lucide-react";

export function QuickActionSingle() {
  return (
    <div className="flex flex-col gap-4 items-center w-full">
      <QuickActionButton onClick={() => alert("单个按钮点击")}>
        <QuickActionIcon>
          <Sparkles className="size-4" />
        </QuickActionIcon>
        <span>这是一个单独的快速操作按钮</span>
      </QuickActionButton>

      <QuickActionButton onClick={() => alert("无图标按钮点击")}>
        无图标的快速操作按钮
      </QuickActionButton>
    </div>
  );
}

交互示例

交互式示例,展示如何响应按钮点击事件。

"use client";

import * as React from "react";
import {
  QuickActionButton,
  QuickActionGroup,
  QuickActionIcon,
} from "@/components/composed/quick-action/quick-action";
import { Sparkles, FileText, Lightbulb } from "lucide-react";

export function QuickActionInteractive() {
  const [selectedAction, setSelectedAction] = React.useState<string>("");

  const handleActionClick = (action: string) => {
    setSelectedAction(action);
  };

  return (
    <div className="flex flex-col gap-4 w-full">
      <QuickActionGroup>
        <QuickActionButton
          onClick={() => handleActionClick("帮我总结一下这段内容")}
        >
          <QuickActionIcon>
            <Sparkles className="size-4" />
          </QuickActionIcon>
          <span>帮我总结一下这段内容</span>
        </QuickActionButton>
        <QuickActionButton
          onClick={() => handleActionClick("给我列一个学习计划")}
        >
          <QuickActionIcon>
            <FileText className="size-4" />
          </QuickActionIcon>
          <span>给我列一个学习计划</span>
        </QuickActionButton>
        <QuickActionButton
          onClick={() => handleActionClick("解释一下这个概念")}
        >
          <QuickActionIcon>
            <Lightbulb className="size-4" />
          </QuickActionIcon>
          <span>解释一下这个概念</span>
        </QuickActionButton>
      </QuickActionGroup>

      {selectedAction && (
        <div className="p-4 rounded-lg bg-[var(--Container-bg-neutral-light)] text-[var(--Text-text-primary)] text-sm">
          <p className="font-medium mb-1">已选择操作:</p>
          <p>{selectedAction}</p>
        </div>
      )}
    </div>
  );
}

禁用状态

禁用状态的快速操作按钮。

"use client";

import {
  QuickActionButton,
  QuickActionGroup,
  QuickActionIcon,
} from "@/components/composed/quick-action/quick-action";
import { Sparkles } from "lucide-react";

export function QuickActionDisabled() {
  return (
    <QuickActionGroup>
      <QuickActionButton onClick={() => alert("这个按钮是可用的")}>
        <QuickActionIcon>
          <Sparkles className="size-4" />
        </QuickActionIcon>
        <span>可用的按钮</span>
      </QuickActionButton>
      <QuickActionButton disabled>
        <QuickActionIcon>
          <Sparkles className="size-4" />
        </QuickActionIcon>
        <span>禁用的按钮</span>
      </QuickActionButton>
      <QuickActionButton disabled>无图标的禁用按钮</QuickActionButton>
    </QuickActionGroup>
  );
}

灵活布局

灵活的内容布局,图标可以放在任意位置。

图标在前面(默认)

图标在后面

两侧都有图标

纯图标按钮

无图标按钮

"use client";

import {
  QuickActionButton,
  QuickActionGroup,
  QuickActionIcon,
} from "@/components/composed/quick-action/quick-action";
import { Sparkles, ChevronRight, Zap, ArrowRight } from "lucide-react";

export function QuickActionFlexibleLayout() {
  return (
    <div className="flex flex-col gap-6 w-full">
      <div>
        <h4 className="text-sm font-medium text-[var(--Text-text-primary)] mb-3">
          图标在前面(默认)
        </h4>
        <QuickActionGroup>
          <QuickActionButton>
            <QuickActionIcon>
              <Sparkles className="size-4" />
            </QuickActionIcon>
            <span>帮我总结内容</span>
          </QuickActionButton>
        </QuickActionGroup>
      </div>

      <div>
        <h4 className="text-sm font-medium text-[var(--Text-text-primary)] mb-3">
          图标在后面
        </h4>
        <QuickActionGroup>
          <QuickActionButton>
            <span>查看更多</span>
            <QuickActionIcon>
              <ChevronRight className="size-4" />
            </QuickActionIcon>
          </QuickActionButton>
        </QuickActionGroup>
      </div>

      <div>
        <h4 className="text-sm font-medium text-[var(--Text-text-primary)] mb-3">
          两侧都有图标
        </h4>
        <QuickActionGroup>
          <QuickActionButton>
            <QuickActionIcon>
              <Zap className="size-4" />
            </QuickActionIcon>
            <span>快速开始</span>
            <QuickActionIcon>
              <ArrowRight className="size-4" />
            </QuickActionIcon>
          </QuickActionButton>
        </QuickActionGroup>
      </div>

      <div>
        <h4 className="text-sm font-medium text-[var(--Text-text-primary)] mb-3">
          纯图标按钮
        </h4>
        <QuickActionGroup>
          <QuickActionButton aria-label="Sparkles">
            <QuickActionIcon>
              <Sparkles className="size-5" />
            </QuickActionIcon>
          </QuickActionButton>
          <QuickActionButton aria-label="Zap">
            <QuickActionIcon>
              <Zap className="size-5" />
            </QuickActionIcon>
          </QuickActionButton>
        </QuickActionGroup>
      </div>

      <div>
        <h4 className="text-sm font-medium text-[var(--Text-text-primary)] mb-3">
          无图标按钮
        </h4>
        <QuickActionGroup>
          <QuickActionButton>简单文本</QuickActionButton>
          <QuickActionButton>另一个操作</QuickActionButton>
        </QuickActionGroup>
      </div>
    </div>
  );
}

API

QuickActionPanel

快速操作面板组件,数据驱动的完整解决方案。

Props

PropTypeDefaultDescription
titlestring-面板标题(可选)
descriptionstring-面板描述文本(可选)
itemsQuickActionItem[]-操作项数组(必填)
onActionClick(text: string) => void-点击操作时的回调函数
classNamestring-额外的样式类名

QuickActionItem Type

interface QuickActionItem {
  text: string;           // 操作按钮文本
  icon?: LucideIcon;      // 可选图标组件
  disabled?: boolean;     // 是否禁用
  onClick?: () => void;   // 自定义点击处理(优先级高于 onActionClick)
}

Example

import { QuickActionPanel } from "@/registry/wuhan/composed/quick-action";
import { MessageSquare, FileText, Code, Settings } from "lucide-react";

function QuickActions() {
  const actions = [
    { text: "开始新对话", icon: MessageSquare },
    { text: "查看文档", icon: FileText },
    { text: "示例代码", icon: Code },
    { text: "设置选项", icon: Settings, disabled: true },
  ];
  
  return (
    <QuickActionPanel
      title="快速开始"
      description="选择一个操作开始使用"
      items={actions}
      onActionClick={(text) => {
        console.log("Clicked:", text);
        // 执行相应操作
      }}
    />
  );
}

QuickActionButton

单个快速操作按钮组件。

Props

PropTypeDefaultDescription
childrenReactNode-按钮文本内容(必填)
disabledbooleanfalse是否禁用
onClick() => void-点击事件处理函数
classNamestring-额外的样式类名

Example

import { QuickActionButton } from "@/registry/wuhan/composed/quick-action";

function SingleAction() {
  return (
    <QuickActionButton onClick={() => console.log("clicked")}>
      点击这里
    </QuickActionButton>
  );
}

QuickActionIcon

快速操作图标组件。

Props

PropTypeDefaultDescription
iconLucideIcon-Lucide 图标组件(必填)
classNamestring-额外的样式类名

Example

import { QuickActionIcon } from "@/registry/wuhan/composed/quick-action";
import { Sparkles } from "lucide-react";

function IconExample() {
  return <QuickActionIcon icon={Sparkles} />;
}

QuickActionGroup

快速操作按钮组容器。

Props

PropTypeDefaultDescription
childrenReactNode-子元素(通常是 QuickActionButton)
classNamestring-额外的样式类名

Example

import { QuickActionGroup, QuickActionButton } from "@/registry/wuhan/composed/quick-action";

function ActionGroup() {
  return (
    <QuickActionGroup>
      <QuickActionButton>操作 1</QuickActionButton>
      <QuickActionButton>操作 2</QuickActionButton>
      <QuickActionButton>操作 3</QuickActionButton>
    </QuickActionGroup>
  );
}

使用场景

  • 空状态引导:新用户首次使用时展示可用操作
  • 聊天界面:对话开始前的快捷问题或操作建议
  • 工作流引导:引导用户完成多步骤流程
  • 功能发现:帮助用户发现产品功能
  • 快捷操作:提供常用功能的快速入口
  • 错误恢复:操作失败后提供可选的下一步操作

最佳实践

  1. 标题描述:使用简洁的标题和描述,说明操作的目的
  2. 操作数量:建议 3-6 个操作,避免选择过载
  3. 图标使用:为每个操作配置相关图标,增强识别性
  4. 文本清晰:操作文本应明确,让用户知道点击后会发生什么
  5. 禁用状态:对不可用的操作使用禁用状态,而非隐藏
  6. 响应式:确保在移动端和桌面端都有良好的显示效果

注意事项

  • titledescription 都是可选的,可以只使用其中之一
  • QuickActionItem 中的 onClick 优先级高于 QuickActionPanelonActionClick
  • 禁用的按钮不会触发点击事件
  • 图标使用 Lucide React,确保已安装该依赖
  • 按钮会自动换行,适应容器宽度

原语组件

Quick Action 基于以下原语组件构建:

  • QuickActionGroupPrimitive - 按钮组容器原语
  • QuickActionButtonPrimitive - 单个按钮原语
  • QuickActionIconPrimitive - 图标容器原语

原语组件提供了基础的样式和结构,可以在 registry/wuhan/blocks/quick-action/quick-action-01.tsx 中找到。

样式定制

组件使用 Tailwind CSS,可以通过以下方式定制:

// 自定义按钮样式
<QuickActionButton 
  className="bg-primary text-primary-foreground hover:bg-primary/90"
>
  自定义样式
</QuickActionButton>

// 自定义面板样式
<QuickActionPanel
  items={items}
  className="p-6 border-2 rounded-xl"
/>

// 自定义图标样式
<QuickActionIcon 
  icon={Sparkles}
  className="text-primary"
/>

扩展示例

聊天空状态

import { QuickActionPanel } from "@/registry/wuhan/composed/quick-action";
import { MessageSquare, Lightbulb, Code, FileText } from "lucide-react";

function ChatEmptyState() {
  const actions = [
    { text: "开始新对话", icon: MessageSquare },
    { text: "获取建议", icon: Lightbulb },
    { text: "查看示例代码", icon: Code },
    { text: "阅读文档", icon: FileText },
  ];
  
  return (
    <div className="flex items-center justify-center h-screen">
      <div className="max-w-md text-center">
        <h1 className="mb-4 text-3xl font-bold">欢迎使用 AI 助手</h1>
        <QuickActionPanel
          description="选择一个操作开始,或直接在下方输入框中提问"
          items={actions}
          onActionClick={(text) => {
            console.log("Starting action:", text);
            // 处理操作
          }}
        />
      </div>
    </div>
  );
}

工作流引导

import { QuickActionPanel } from "@/registry/wuhan/composed/quick-action";
import { Upload, Edit, Share, Download } from "lucide-react";

function WorkflowGuide() {
  const [step, setStep] = useState(0);
  
  const steps = [
    {
      title: "步骤 1: 上传文件",
      description: "选择要处理的文件",
      actions: [
        { text: "从电脑上传", icon: Upload },
        { text: "从云端导入", icon: Download },
      ],
    },
    {
      title: "步骤 2: 编辑内容",
      description: "对文件进行编辑和调整",
      actions: [
        { text: "开始编辑", icon: Edit },
        { text: "使用模板", icon: FileText },
      ],
    },
    {
      title: "步骤 3: 分享结果",
      description: "完成后分享你的作品",
      actions: [
        { text: "分享链接", icon: Share },
        { text: "下载文件", icon: Download },
      ],
    },
  ];
  
  const currentStep = steps[step];
  
  return (
    <div className="max-w-2xl mx-auto p-6">
      <QuickActionPanel
        title={currentStep.title}
        description={currentStep.description}
        items={currentStep.actions}
        onActionClick={(text) => {
          console.log("Action:", text);
          if (step < steps.length - 1) {
            setStep(step + 1);
          }
        }}
      />
    </div>
  );
}

错误恢复

import { QuickActionPanel } from "@/registry/wuhan/composed/quick-action";
import { RefreshCw, Home, HelpCircle } from "lucide-react";

function ErrorRecovery() {
  const recoveryActions = [
    { 
      text: "重试操作", 
      icon: RefreshCw,
      onClick: () => {
        // 重新执行失败的操作
        console.log("Retrying...");
      }
    },
    { 
      text: "返回首页", 
      icon: Home,
      onClick: () => {
        // 导航到首页
        window.location.href = "/";
      }
    },
    { 
      text: "获取帮助", 
      icon: HelpCircle,
      onClick: () => {
        // 打开帮助中心
        window.open("/help", "_blank");
      }
    },
  ];
  
  return (
    <div className="flex items-center justify-center min-h-screen">
      <div className="max-w-md text-center space-y-4">
        <div className="text-6xl">⚠️</div>
        <h2 className="text-2xl font-bold">操作失败</h2>
        <p className="text-muted-foreground">
          抱歉,操作未能完成。请选择下一步操作。
        </p>
        <QuickActionPanel
          items={recoveryActions}
        />
      </div>
    </div>
  );
}

动态操作列表

import { QuickActionPanel } from "@/registry/wuhan/composed/quick-action";
import { useState, useEffect } from "react";

function DynamicActions() {
  const [actions, setActions] = useState([]);
  const [loading, setLoading] = useState(true);
  
  useEffect(() => {
    // 模拟 API 调用获取可用操作
    setTimeout(() => {
      setActions([
        { text: "推荐操作 1", icon: Sparkles },
        { text: "推荐操作 2", icon: Lightbulb },
        { text: "推荐操作 3", icon: MessageSquare },
      ]);
      setLoading(false);
    }, 1000);
  }, []);
  
  if (loading) {
    return <div className="text-center p-4">加载中...</div>;
  }
  
  return (
    <QuickActionPanel
      title="为你推荐"
      description="基于你的使用习惯,我们为你推荐以下操作"
      items={actions}
      onActionClick={(text) => console.log(text)}
    />
  );
}

分组操作

import { QuickActionGroup, QuickActionButton, QuickActionIcon } from "@/registry/wuhan/composed/quick-action";
import { Code, FileText, MessageSquare, Settings } from "lucide-react";

function GroupedActions() {
  return (
    <div className="space-y-6">
      <div>
        <h3 className="mb-2 text-sm font-medium text-muted-foreground">
          创建内容
        </h3>
        <QuickActionGroup>
          <QuickActionButton>
            <QuickActionIcon icon={Code} />
            新建代码
          </QuickActionButton>
          <QuickActionButton>
            <QuickActionIcon icon={FileText} />
            新建文档
          </QuickActionButton>
        </QuickActionGroup>
      </div>
      
      <div>
        <h3 className="mb-2 text-sm font-medium text-muted-foreground">
          其他操作
        </h3>
        <QuickActionGroup>
          <QuickActionButton>
            <QuickActionIcon icon={MessageSquare} />
            开始对话
          </QuickActionButton>
          <QuickActionButton>
            <QuickActionIcon icon={Settings} />
            设置选项
          </QuickActionButton>
        </QuickActionGroup>
      </div>
    </div>
  );
}