refactor: 枚举移入Models目录,命名空间更新为Rainbow.Entity.Models
大石头 authored at 2026-07-02 12:54:58
2.47 KiB
RainbowBridge
import { type ButtonHTMLAttributes, type ReactNode } from 'react'
import { cn } from '@/lib/utils'

export type ButtonVariant = 'primary' | 'secondary' | 'soft' | 'ghost' | 'danger'
export type ButtonSize = 'sm' | 'md' | 'lg'

interface ButtonProps extends ButtonHTMLAttributes<HTMLButtonElement> {
  variant?: ButtonVariant
  size?: ButtonSize
  icon?: ReactNode
  children?: ReactNode
}

const variantStyles: Record<ButtonVariant, string> = {
  primary:
    'text-white shadow-[0_8px_24px_-8px_rgba(91,91,255,0.45),0_2px_6px_rgba(91,91,255,0.18)] ' +
    'hover:shadow-[0_12px_28px_-8px_rgba(91,91,255,0.55),0_2px_8px_rgba(91,91,255,0.22)] ' +
    'hover:-translate-y-px active:translate-y-0 ' +
    'bg-[image:var(--gradient-brand)] bg-[length:200%_100%] hover:bg-[length:160%_100%]',
  secondary:
    'bg-[var(--color-surface-2)] hover:bg-[var(--color-surface-3)] text-[var(--color-text-primary)] ' +
    'border border-[var(--color-border-subtle)]',
  soft:
    'bg-[image:var(--gradient-brand-soft)] text-[color:var(--color-brand-700)] dark:text-[color:var(--color-brand-300)] ' +
    'hover:brightness-105 border border-[var(--color-border-subtle)]',
  ghost:
    'hover:bg-[var(--color-surface-2)] text-[var(--color-text-secondary)] hover:text-[var(--color-text-primary)]',
  danger:
    'bg-red-500 hover:bg-red-600 text-white shadow-sm hover:shadow-md hover:-translate-y-px active:translate-y-0',
}

const sizeStyles: Record<ButtonSize, string> = {
  sm: 'px-2.5 py-1.5 text-xs rounded-lg',
  md: 'px-4 py-2 text-sm rounded-lg',
  lg: 'px-5 py-2.5 text-base rounded-xl',
}

export function Button({
  variant = 'primary',
  size = 'md',
  icon,
  children,
  className,
  disabled,
  ...props
}: ButtonProps) {
  return (
    <button
      className={cn(
        'inline-flex items-center justify-center font-medium select-none',
        'transition-[transform,box-shadow,background-position,background-color,color] duration-200 ease-out',
        'focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[color:var(--color-brand-500)]/55 focus-visible:ring-offset-1 focus-visible:ring-offset-[var(--color-surface-0)]',
        'disabled:opacity-50 disabled:cursor-not-allowed disabled:shadow-none disabled:translate-y-0 disabled:hover:translate-y-0',
        variantStyles[variant],
        sizeStyles[size],
        icon && children && 'space-x-1.5',
        className,
      )}
      disabled={disabled}
      {...props}
    >
      {icon}
      {children && <span>{children}</span>}
    </button>
  )
}