Axil_website/src/components/ui/Button.tsx
Vadym Samoilenko 7bb25f9c59 feat: add courses page, real contact details, Courses to navigation
- New /courses page with 5 course cards (Interview Ready, Self
  Assessment, Payroll, QuickBooks, Xero) with thumbnail images,
  pricing, includes checklists, and enrol CTAs
- Added course images to public/courses/ and Assets/
- Contact page: updated email, phone (07440 594192), address
  (Suite 29 Beaufort Court E14 9XL), hours, and added Courses
  option to the "I'm interested in" select field
- Header: added Courses to desktop nav and mobile dock
  (GraduationCap icon) between Services and Blog

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-23 13:25:16 +00:00

98 lines
2.5 KiB
TypeScript

'use client';
import { forwardRef } from 'react';
import Link from 'next/link';
import { Spinner } from './Spinner';
import { ArrowRightIcon } from './icons';
type Variant = 'primary' | 'secondary' | 'ghost';
type Size = 'sm' | 'md' | 'lg';
interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {
variant?: Variant;
size?: Size;
loading?: boolean;
trailingArrow?: boolean;
leadingIcon?: React.ReactNode;
href?: string;
}
const variants: Record<Variant, string> = {
primary:
'bg-emerald text-white hover:bg-emerald-dark active:bg-emerald-deeper ' +
'focus-visible:ring-emerald/50 shadow-sm',
secondary:
'border border-emerald text-emerald bg-transparent hover:bg-emerald-mist ' +
'focus-visible:ring-emerald/50',
ghost: 'text-emerald bg-transparent hover:bg-emerald-mist ' + 'focus-visible:ring-emerald/50',
};
const sizes: Record<Size, string> = {
sm: 'h-9 px-4 text-sm gap-1.5 rounded-pill',
md: 'h-11 px-6 text-base gap-2 rounded-pill',
lg: 'h-14 px-8 text-lg gap-2.5 rounded-pill',
};
export const Button = forwardRef<HTMLButtonElement, ButtonProps>(
(
{
variant = 'primary',
size = 'md',
loading = false,
trailingArrow = false,
leadingIcon,
children,
className = '',
disabled,
href,
...props
},
ref,
) => {
const arrowSize = size === 'sm' ? 14 : size === 'lg' ? 20 : 16;
const classes = [
'inline-flex cursor-pointer items-center justify-center font-medium',
'transition-all duration-200',
'focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:outline-none',
'active:scale-[0.98]',
'disabled:cursor-not-allowed disabled:opacity-50 disabled:active:scale-100',
variants[variant],
sizes[size],
className,
].join(' ');
const content = (
<>
{loading ? (
<Spinner size={size === 'lg' ? 'md' : 'sm'} />
) : leadingIcon ? (
leadingIcon
) : null}
{children}
{!loading && trailingArrow && (
<ArrowRightIcon
size={arrowSize}
className="shrink-0 transition-transform duration-200 group-hover:translate-x-0.5"
/>
)}
</>
);
if (href) {
return (
<Link href={href} className={classes}>
{content}
</Link>
);
}
return (
<button ref={ref} disabled={disabled || loading} className={classes} {...props}>
{content}
</button>
);
},
);
Button.displayName = 'Button';