Spaces:
Sleeping
Sleeping
| "use client"; | |
| import { forwardRef } from "react"; | |
| import { cn } from "@/lib/utils"; | |
| interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> { | |
| variant?: "primary" | "secondary" | "ghost" | "danger"; | |
| size?: "sm" | "md" | "lg"; | |
| loading?: boolean; | |
| } | |
| export const Button = forwardRef<HTMLButtonElement, ButtonProps>( | |
| ({ className, variant = "primary", size = "md", loading, children, disabled, ...props }, ref) => { | |
| const base = | |
| "inline-flex items-center justify-center gap-2 font-semibold rounded-xl transition-all duration-200 focus:outline-none focus-visible:ring-2 focus-visible:ring-offset-2 disabled:opacity-50 disabled:cursor-not-allowed"; | |
| const variants = { | |
| primary: | |
| "bg-gradient-to-br from-brand-green-light to-brand-green text-white shadow-md shadow-brand-green/25 hover:shadow-lg hover:shadow-brand-green/30 hover:brightness-105 focus-visible:ring-brand-green", | |
| secondary: | |
| "bg-white border-1.5 border-neutral-200 text-neutral-700 hover:border-brand-green hover:text-brand-green hover:bg-brand-green-50 focus-visible:ring-brand-green", | |
| ghost: | |
| "bg-transparent text-neutral-600 hover:bg-neutral-100 hover:text-neutral-900 focus-visible:ring-neutral-400", | |
| danger: | |
| "bg-red-500 text-white hover:bg-red-600 shadow-sm focus-visible:ring-red-500", | |
| }; | |
| const sizes = { | |
| sm: "px-3 py-1.5 text-xs", | |
| md: "px-5 py-2.5 text-sm", | |
| lg: "px-7 py-3.5 text-base", | |
| }; | |
| return ( | |
| <button | |
| ref={ref} | |
| disabled={disabled || loading} | |
| className={cn(base, variants[variant], sizes[size], className)} | |
| {...props} | |
| > | |
| {loading && ( | |
| <svg | |
| className="animate-spin h-4 w-4" | |
| xmlns="http://www.w3.org/2000/svg" | |
| fill="none" | |
| viewBox="0 0 24 24" | |
| > | |
| <circle className="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" strokeWidth="4" /> | |
| <path | |
| className="opacity-75" | |
| fill="currentColor" | |
| d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4z" | |
| /> | |
| </svg> | |
| )} | |
| {children} | |
| </button> | |
| ); | |
| } | |
| ); | |
| Button.displayName = "Button"; | |