Files
Claude bca3745603 feat: pivot complet - agence web artisans BTP Nord + Sanity CMS
Transformation complète du site HookLab de formation TikTok Shop
vers une landing page haute conversion pour agence web locale ciblant
les artisans du bâtiment dans le Nord (Douai, Orchies, Valenciennes).

- Nouveau design system : bleu nuit/orange sur fond clair (mobile-first)
- Hero avec promesse artisan + CTA orange "Réserver mon Audit"
- Section "Le Système" (3 étapes : Trouvé, Choisi, Contacté)
- Portfolio connecté à Sanity.io (fallback data intégré)
- Section "Qui suis-je" avec carte OpenStreetMap interactive
- FAQ orientée artisans avec JSON-LD pour Google
- Formulaire contact audit gratuit
- SEO local : 12 keywords artisans, JSON-LD LocalBusiness
- Sanity.io schemas (portfolio, siteSettings) + client conditionnel
- Accessibilité : skip-to-content, focus-visible, aria-labels

https://claude.ai/code/session_01H2aRGDaKgarPvhay2HxN6Y
2026-02-15 12:50:52 +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-xl cursor-pointer disabled:opacity-50 disabled:cursor-not-allowed";
const variants = {
primary:
"bg-orange text-white hover:bg-orange-hover hover:translate-y-[-1px] hover:shadow-lg",
secondary:
"bg-navy text-white hover:bg-navy-light hover:translate-y-[-1px] hover:shadow-lg",
outline:
"bg-transparent text-navy border-2 border-navy hover:bg-navy hover:text-white",
ghost:
"bg-transparent text-text-light hover:text-navy hover:bg-bg-muted",
};
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;