/**
* Stepper 步骤条组件 — 用于多步骤工作流引导
* 支持横向/纵向布局、可点击步骤导航、完成/当前/待办状态
*/
import clsx from 'clsx'
import { Check } from 'lucide-react'
export interface Step {
key: string
title: string
description?: string
status: 'complete' | 'current' | 'pending' | 'error'
}
interface StepperProps {
steps: Step[]
orientation?: 'horizontal' | 'vertical'
onStepClick?: (key: string) => void
className?: string
}
/**
* Stepper 步骤条 — 展示工作流进度和步骤导航
*/
export function Stepper({ steps, orientation = 'horizontal', onStepClick, className }: StepperProps) {
if (orientation === 'vertical') {
return (
{steps.map((step, i) => {
const isLast = i === steps.length - 1
const isClickable = onStepClick && (step.status === 'complete' || step.status === 'current')
return (
{/* 左侧指示器 + 连接线 */}
{!isLast && (
)}
{/* 右侧内容 */}
onStepClick?.(step.key) : undefined}
className={clsx(
'text-sm font-medium',
step.status === 'current' && 'text-ink-900',
step.status === 'complete' && 'text-ink-700',
step.status === 'pending' && 'text-ink-400',
step.status === 'error' && 'text-danger',
isClickable && 'cursor-pointer hover:text-ink-900',
)}
>
{step.title}
{step.description && (
{step.description}
)}
)
})}
)
}
// 横向布局
return (
{steps.map((step, i) => {
const isLast = i === steps.length - 1
const isClickable = onStepClick && (step.status === 'complete' || step.status === 'current')
return (
{/* 圆点 + 标题 */}
onStepClick?.(step.key) : undefined}
className={clsx(
'text-sm font-medium whitespace-nowrap',
step.status === 'current' && 'text-ink-900',
step.status === 'complete' && 'text-ink-700',
step.status === 'pending' && 'text-ink-400',
step.status === 'error' && 'text-danger',
isClickable && 'cursor-pointer hover:text-ink-900',
)}
>
{step.title}
{step.description && (
{step.description}
)}
{/* 连接线 */}
{!isLast && (
)}
)
})}
)
}