Files
obc-terrassement/components/ui/Button.tsx
Claude 41e686c560 feat: complete HookLab MVP - TikTok Shop coaching platform
Full-stack Next.js 15 application with:
- Landing page with marketing components (Hero, Testimonials, Pricing, FAQ)
- Multi-step candidature form with API route
- Stripe Checkout integration (subscription + webhooks)
- Supabase Auth (login/register) with middleware protection
- Dashboard with progress tracking and module system
- Formations pages with completion tracking
- Profile management with password change
- Database schema with RLS policies
- Resend email integration for transactional emails

Stack: Next.js 15, TypeScript, Tailwind CSS v4, Supabase, Stripe, Resend

https://claude.ai/code/session_01H2aRGDaKgarPvhay2HxN6Y
2026-02-08 12:39:18 +00:00

86 lines
2.2 KiB
TypeScript

"use client";
import { cn } from "@/lib/utils";
import { ButtonHTMLAttributes, forwardRef } from "react";
interface ButtonProps extends ButtonHTMLAttributes<HTMLButtonElement> {
variant?: "primary" | "secondary" | "outline" | "ghost";
size?: "sm" | "md" | "lg";
loading?: boolean;
}
const Button = forwardRef<HTMLButtonElement, ButtonProps>(
(
{
className,
variant = "primary",
size = "md",
loading = false,
disabled,
children,
...props
},
ref
) => {
const baseStyles =
"inline-flex items-center justify-center font-semibold transition-all duration-300 rounded-[12px] cursor-pointer disabled:opacity-50 disabled:cursor-not-allowed";
const variants = {
primary:
"gradient-bg text-white hover:opacity-90 hover:translate-y-[-2px] hover:shadow-lg",
secondary:
"bg-dark-light text-white border border-dark-border hover:border-primary/50 hover:translate-y-[-2px]",
outline:
"bg-transparent text-primary border-2 border-primary hover:bg-primary hover:text-white",
ghost:
"bg-transparent text-white/70 hover:text-white hover:bg-white/5",
};
const sizes = {
sm: "px-4 py-2 text-sm",
md: "px-6 py-3 text-base",
lg: "px-8 py-4 text-lg",
};
return (
<button
ref={ref}
className={cn(baseStyles, variants[variant], sizes[size], className)}
disabled={disabled || loading}
{...props}
>
{loading ? (
<span className="flex items-center gap-2">
<svg
className="animate-spin h-4 w-4"
viewBox="0 0 24 24"
fill="none"
>
<circle
className="opacity-25"
cx="12"
cy="12"
r="10"
stroke="currentColor"
strokeWidth="4"
/>
<path
className="opacity-75"
fill="currentColor"
d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4z"
/>
</svg>
Chargement...
</span>
) : (
children
)}
</button>
);
}
);
Button.displayName = "Button";
export default Button;