Write on the margins of the internet. Powered by the AT Protocol. margin.at
extension web atproto comments
at main 76 lines 2.1 kB view raw
1import React from "react"; 2import { clsx } from "clsx"; 3 4type ButtonVariant = "primary" | "secondary" | "ghost" | "danger"; 5type ButtonSize = "sm" | "md" | "lg"; 6 7interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> { 8 variant?: ButtonVariant; 9 size?: ButtonSize; 10 loading?: boolean; 11 icon?: React.ReactNode; 12 children?: React.ReactNode; 13} 14 15const variants: Record<ButtonVariant, string> = { 16 primary: "bg-primary-600 text-white hover:bg-primary-500 shadow-sm", 17 secondary: 18 "bg-surface-100 dark:bg-surface-800 text-surface-900 dark:text-white hover:bg-surface-200 dark:hover:bg-surface-700", 19 ghost: 20 "text-surface-600 dark:text-surface-400 hover:bg-surface-100 dark:hover:bg-surface-800 hover:text-surface-900 dark:hover:text-white", 21 danger: "bg-red-600 text-white hover:bg-red-500", 22}; 23 24const sizes: Record<ButtonSize, string> = { 25 sm: "px-3 py-1.5 text-sm gap-1.5", 26 md: "px-4 py-2 text-sm gap-2", 27 lg: "px-6 py-3 text-base gap-2", 28}; 29 30export default function Button({ 31 variant = "primary", 32 size = "md", 33 loading = false, 34 icon, 35 children, 36 className, 37 disabled, 38 ...props 39}: ButtonProps) { 40 return ( 41 <button 42 className={clsx( 43 "inline-flex items-center justify-center font-medium rounded-lg transition-all duration-200", 44 "focus:outline-none focus:ring-2 focus:ring-primary-500/20", 45 "disabled:opacity-50 disabled:cursor-not-allowed", 46 variants[variant], 47 sizes[size], 48 className, 49 )} 50 disabled={disabled || loading} 51 {...props} 52 > 53 {loading ? ( 54 <svg className="animate-spin h-4 w-4" viewBox="0 0 24 24"> 55 <circle 56 className="opacity-25" 57 cx="12" 58 cy="12" 59 r="10" 60 stroke="currentColor" 61 strokeWidth="4" 62 fill="none" 63 /> 64 <path 65 className="opacity-75" 66 fill="currentColor" 67 d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4z" 68 /> 69 </svg> 70 ) : ( 71 icon 72 )} 73 {children && <span>{children}</span>} 74 </button> 75 ); 76}