| import React from "react"; | |
| import { cn } from "@/lib/utils/cn"; | |
| interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> { | |
| variant?: "primary" | "secondary" | "outline" | "ghost" | "danger"; | |
| size?: "sm" | "md" | "lg"; | |
| isLoading?: boolean; | |
| } | |
| export const Button: React.FC<ButtonProps> = ({ | |
| children, | |
| variant = "primary", | |
| size = "md", | |
| isLoading = false, | |
| disabled, | |
| className, | |
| ...props | |
| }) => { | |
| const baseStyles = "inline-flex items-center justify-center rounded-xl font-semibold transition-all duration-250 ease-out focus:outline-none focus:ring-2 focus:ring-offset-2 disabled:opacity-50 disabled:pointer-events-none relative overflow-hidden group"; | |
| const variants = { | |
| primary: "bg-gradient-to-r from-blue-500 to-cyan-500 text-white hover:from-blue-600 hover:to-cyan-600 focus:ring-blue-500 shadow-lg hover:shadow-xl hover:scale-105 active:scale-100", | |
| secondary: "bg-gradient-to-r from-orange-400 to-pink-500 text-white hover:from-orange-500 hover:to-pink-600 focus:ring-orange-500 shadow-lg hover:shadow-xl hover:scale-105 active:scale-100", | |
| outline: "border-2 border-gray-300 text-gray-700 hover:bg-gray-50 focus:ring-gray-500 hover:border-gray-400 hover:scale-105 active:scale-100 bg-white/50 backdrop-blur-sm", | |
| ghost: "text-gray-700 hover:bg-gray-100/80 focus:ring-gray-500 hover:scale-105 active:scale-100", | |
| danger: "bg-gradient-to-r from-red-500 to-red-600 text-white hover:from-red-600 hover:to-red-700 focus:ring-red-500 shadow-lg hover:shadow-xl hover:scale-105 active:scale-100", | |
| }; | |
| const sizes = { | |
| sm: "px-4 py-2 text-sm", | |
| md: "px-6 py-3 text-base", | |
| lg: "px-8 py-4 text-lg", | |
| }; | |
| return ( | |
| <button | |
| className={cn(baseStyles, variants[variant], sizes[size], className)} | |
| disabled={disabled || isLoading} | |
| {...props} | |
| > | |
| {/* Shine effect on hover */} | |
| <span className="absolute inset-0 -translate-x-full group-hover:translate-x-full transition-transform duration-700 bg-gradient-to-r from-transparent via-white/20 to-transparent"></span> | |
| {isLoading ? ( | |
| <> | |
| <svg className="animate-spin -ml-1 mr-2 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"></circle> | |
| <path className="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"></path> | |
| </svg> | |
| Loading... | |
| </> | |
| ) : ( | |
| <span className="relative z-10 flex items-center">{children}</span> | |
| )} | |
| </button> | |
| ); | |
| }; | |