9router / src /shared /components /Button.js
2api
feat: configurable stream stall timeout + per-provider UI
88c4c60
Raw
History Blame Contribute Delete
1.86 kB
"use client";
import { cn } from "@/shared/utils/cn";
const variants = {
primary: "bg-brand-500 hover:bg-brand-600 text-white shadow-sm disabled:bg-surface-3 disabled:text-text-muted",
secondary: "bg-surface-2 hover:bg-surface-3 text-text-main border border-border disabled:opacity-50",
outline: "border border-border text-text-main hover:bg-surface-2 hover:border-brand-500/40",
ghost: "text-text-muted hover:bg-surface-2 hover:text-text-main",
danger: "bg-red-500 hover:bg-red-600 text-white shadow-sm disabled:bg-surface-3 disabled:text-text-muted",
success: "bg-green-600 hover:bg-green-700 text-white shadow-sm disabled:bg-surface-3 disabled:text-text-muted",
};
const sizes = {
sm: "h-7 px-3 text-xs rounded-[8px]",
md: "h-9 px-4 text-sm rounded-[10px]",
lg: "h-11 px-6 text-sm rounded-[10px]",
};
export default function Button({
children,
variant = "primary",
size = "md",
icon,
iconRight,
disabled = false,
loading = false,
fullWidth = false,
className,
...props
}) {
return (
<button
className={cn(
"inline-flex items-center justify-center gap-2 font-semibold transition-all duration-150 ease-out cursor-pointer",
"active:scale-[0.97] disabled:opacity-50 disabled:cursor-not-allowed disabled:active:scale-100",
variants[variant],
sizes[size],
fullWidth && "w-full",
className
)}
disabled={disabled || loading}
{...props}
>
{loading ? (
<span className="material-symbols-outlined animate-spin text-[18px]">progress_activity</span>
) : icon ? (
<span className="material-symbols-outlined text-[18px]">{icon}</span>
) : null}
{children}
{iconRight && !loading && (
<span className="material-symbols-outlined text-[18px]">{iconRight}</span>
)}
</button>
);
}