shinroute / src /shared /components /Button.tsx
shinmentakezo07
Add OmniRoute codebase without binary assets
9e4583c
Raw
History Blame Contribute Delete
2.31 kB
"use client";
import { cn } from "@/shared/utils/cn";
const variants = {
primary: "bg-gradient-to-b from-primary to-primary-hover text-white shadow-sm",
secondary:
"bg-white dark:bg-white/10 border border-black/10 dark:border-white/10 text-text-main hover:bg-black/5 dark:hover:bg-white/5",
outline: "border border-black/15 dark:border-white/15 text-text-main hover:bg-black/5",
ghost: "text-text-muted hover:bg-black/5 dark:hover:bg-white/5 hover:text-text-main",
danger: "bg-red-500 text-white hover:bg-red-600 shadow-sm",
};
const sizes = {
sm: "h-7 px-3 text-xs rounded-md",
md: "h-9 px-4 text-sm rounded-lg",
lg: "h-11 px-6 text-sm rounded-lg",
};
interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {
children?: React.ReactNode;
variant?: keyof typeof variants;
size?: keyof typeof sizes;
icon?: string;
iconRight?: string;
loading?: boolean;
fullWidth?: boolean;
className?: string;
}
export default function Button({
children,
variant = "primary",
size = "md",
icon,
iconRight,
disabled = false,
loading = false,
fullWidth = false,
className,
...props
}: ButtonProps) {
return (
<button
type="button"
className={cn(
"inline-flex items-center justify-center gap-2 font-medium transition-all duration-200 cursor-pointer",
"active:scale-[0.99] disabled:opacity-50 disabled:cursor-not-allowed disabled:active:scale-100",
variants[variant],
sizes[size],
fullWidth && "w-full",
className
)}
disabled={disabled || loading}
aria-busy={loading || undefined}
{...props}
>
{loading ? (
<span
className="material-symbols-outlined animate-spin text-[18px] pointer-events-none"
aria-hidden="true"
>
progress_activity
</span>
) : icon ? (
<span
className="material-symbols-outlined text-[18px] pointer-events-none"
aria-hidden="true"
>
{icon}
</span>
) : null}
{children}
{iconRight && !loading && (
<span
className="material-symbols-outlined text-[18px] pointer-events-none"
aria-hidden="true"
>
{iconRight}
</span>
)}
</button>
);
}