56 lines
1.6 KiB
TypeScript
56 lines
1.6 KiB
TypeScript
import React from 'react';
|
|
|
|
type ButtonVariant = 'primary' | 'secondary' | 'ghost' | 'danger';
|
|
type ButtonSize = 'sm' | 'md' | 'lg';
|
|
|
|
interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {
|
|
variant?: ButtonVariant;
|
|
size?: ButtonSize;
|
|
loading?: boolean;
|
|
}
|
|
|
|
const variantStyles: Record<ButtonVariant, string> = {
|
|
primary:
|
|
'bg-[#ff4500] text-[#111] border-[#ff4500] hover:bg-[#111] hover:text-[#ff4500]',
|
|
secondary:
|
|
'bg-transparent text-[#e0e0e0] border-[#555] hover:bg-[#e0e0e0] hover:text-[#111]',
|
|
ghost:
|
|
'bg-transparent text-[#888] border-[#333] hover:border-[#e0e0e0] hover:text-[#e0e0e0]',
|
|
danger:
|
|
'bg-transparent text-[#cc3300] border-[#cc3300] hover:bg-[#cc3300] hover:text-[#111]',
|
|
};
|
|
|
|
const sizeStyles: Record<ButtonSize, string> = {
|
|
sm: 'px-4 py-2 text-[15px]',
|
|
md: 'px-6 py-3 text-[34px]',
|
|
lg: 'px-8 py-4 text-[15px]',
|
|
};
|
|
|
|
export default function Button({
|
|
variant = 'primary',
|
|
size = 'md',
|
|
loading,
|
|
disabled,
|
|
className = '',
|
|
children,
|
|
...props
|
|
}: ButtonProps) {
|
|
return (
|
|
<button
|
|
disabled={disabled || loading}
|
|
className={`inline-flex items-center justify-center gap-2 font-semibold tracking-[0.08em] uppercase
|
|
border transition-colors duration-75
|
|
${variantStyles[variant]}
|
|
${sizeStyles[size]}
|
|
${disabled ? 'opacity-40 cursor-not-allowed' : 'cursor-pointer'}
|
|
${className}`}
|
|
{...props}
|
|
>
|
|
{loading && (
|
|
<span className="w-3 h-3 border border-current border-t-transparent animate-spin" />
|
|
)}
|
|
{!loading && children}
|
|
</button>
|
|
);
|
|
}
|