| "use client"; | |
| import { cn } from "@/lib/utils"; | |
| import { Loader2 } from "lucide-react"; | |
| import type { ButtonHTMLAttributes, ReactNode } from "react"; | |
| interface ButtonProps extends ButtonHTMLAttributes<HTMLButtonElement> { | |
| variant?: "primary" | "secondary" | "ghost" | "danger"; | |
| size?: "sm" | "md" | "lg"; | |
| loading?: boolean; | |
| children: ReactNode; | |
| } | |
| export function Button({ | |
| variant = "primary", | |
| size = "md", | |
| loading = false, | |
| className, | |
| children, | |
| disabled, | |
| ...props | |
| }: ButtonProps) { | |
| const variants = { | |
| primary: | |
| "bg-accent text-root hover:bg-accent-hover font-semibold", | |
| secondary: | |
| "bg-surface text-primary border border-edge hover:bg-raised", | |
| ghost: | |
| "bg-transparent text-secondary hover:text-primary hover:bg-raised", | |
| danger: | |
| "bg-danger text-white hover:brightness-110", | |
| }; | |
| const sizes = { | |
| sm: "px-3 py-1.5 text-xs gap-1.5", | |
| md: "px-4 py-2.5 text-sm gap-2", | |
| lg: "px-6 py-3 text-sm gap-2", | |
| }; | |
| return ( | |
| <button | |
| className={cn( | |
| "inline-flex items-center justify-center rounded-lg font-medium transition-all duration-150 disabled:opacity-40 disabled:cursor-not-allowed", | |
| variants[variant], | |
| sizes[size], | |
| className | |
| )} | |
| disabled={disabled || loading} | |
| {...props} | |
| > | |
| {loading && <Loader2 className="h-4 w-4 animate-spin" />} | |
| {children} | |
| </button> | |
| ); | |
| } | |