spb/phi-conseil
Public
1import Link from "next/link";2import type { ComponentPropsWithoutRef, ReactNode } from "react";34type Variant = "primary" | "ivory" | "outline" | "ghost";5type Size = "md" | "lg";67const base =8 "inline-flex items-center justify-center gap-2 rounded-pill font-medium transition-[background-color,color,box-shadow,transform] duration-[var(--duration-base)] ease-[var(--ease-out)] focus-visible:outline-3 focus-visible:outline-offset-2 disabled:cursor-not-allowed disabled:opacity-60 motion-safe:hover:-translate-y-px";910const variants: Record<Variant, string> = {11 primary: "bg-slate-500 text-white shadow-sm hover:bg-slate-700 focus-visible:outline-navy-900",12 ivory: "bg-ivory-200 text-navy-900 hover:bg-ivory-100 focus-visible:outline-white",13 outline:14 "border border-navy-800/50 bg-transparent text-navy-900 hover:border-navy-900 hover:bg-white/60",15 ghost: "text-navy-900 hover:bg-navy-900/5",16};1718const sizes: Record<Size, string> = {19 md: "px-5 py-2 text-sm",20 lg: "px-6 py-3 text-[0.95rem]",21};2223export function Arrow({ className = "h-4 w-4" }: { className?: string }) {24 return (25 <svg26 className={className}27 viewBox="0 0 16 16"28 fill="none"29 stroke="currentColor"30 strokeWidth="1.6"31 strokeLinecap="round"32 strokeLinejoin="round"33 aria-hidden="true"34 >35 <path d="M2.5 8h11M9 3.5 13.5 8 9 12.5" />36 </svg>37 );38}3940type CommonProps = {41 variant?: Variant;42 size?: Size;43 arrow?: boolean;44 className?: string;45 children: ReactNode;46};4748type LinkProps = CommonProps & { href: string } & Omit<49 ComponentPropsWithoutRef<typeof Link>,50 "href" | "children" | "className"51 >;52type ButtonProps = CommonProps & { href?: undefined } & Omit<53 ComponentPropsWithoutRef<"button">,54 "children" | "className"55 >;5657export function Button(props: LinkProps | ButtonProps) {58 const {59 variant = "primary",60 size = "md",61 arrow = true,62 className = "",63 children,64 ...rest65 } = props;66 const cls = `${base} ${variants[variant]} ${sizes[size]} ${className}`;67 const content = (68 <>69 {children}70 {arrow ? <Arrow /> : null}71 </>72 );73 if (rest.href !== undefined) {74 const { href, ...linkRest } = rest as Omit<LinkProps, keyof CommonProps>;75 return (76 <Link href={href} className={cls} {...linkRest}>77 {content}78 </Link>79 );80 }81 const { href: _unused, ...buttonRest } = rest as Omit<ButtonProps, keyof CommonProps>;82 void _unused;83 return (84 <button type="button" className={cls} {...buttonRest}>85 {content}86 </button>87 );88}89