feat: rebuild 3 demo pages with interactive features + local SEO pages

- Rebuild /macon with cert badge popups, before/after slider, intelligent
  form with urgency detection
- Rebuild /paysagiste with filterable gallery, seasonal banner, WhatsApp
  floating button, devis form
- Rebuild /plombier with sticky call bar, 3-step diagnostic wizard,
  transparent tariffs, zone map
- Add MagicReveal component (interactive before/after slider)
- Update Navbar with real phone number (06 04 40 81 57)
- Update DemosLive cards with new titles and subtitles
- Create sitemap.ts targeting local SEO zones (Douai, Orchies,
  Valenciennes, Saint-Amand, Arleux, Denain)
- Create LocalSeoPage template + 6 city-specific landing pages

https://claude.ai/code/session_01H2aRGDaKgarPvhay2HxN6Y
This commit is contained in:
Claude
2026-02-15 22:10:14 +00:00
parent a845b47316
commit 9025986e66
17 changed files with 1331 additions and 259 deletions

197
app/macon/MaconClient.tsx Normal file
View File

@@ -0,0 +1,197 @@
"use client";
import { useState } from "react";
import MagicReveal from "@/components/ui/MagicReveal";
import Button from "@/components/ui/Button";
interface MaconClientProps {
type?: "slider" | "form" | "cert";
certName?: string;
avantLabel?: string;
apresLabel?: string;
}
export default function MaconClient({ type, certName, avantLabel, apresLabel }: MaconClientProps) {
// Cert badge with popup
if (!type || type === "cert") {
return <CertBadge name={certName || ""} />;
}
if (type === "slider") {
return (
<MagicReveal
avantLabel={avantLabel || ""}
apresLabel={apresLabel || ""}
avantColor="bg-red-50"
apresColor="bg-green-50"
height="h-64"
/>
);
}
if (type === "form") {
return <DevisForm />;
}
return null;
}
function CertBadge({ name }: { name: string }) {
const [open, setOpen] = useState(false);
const infos: Record<string, string> = {
"D\u00e9cennale": "La garantie d\u00e9cennale couvre tous les dommages compromettant la solidit\u00e9 de l\u2019ouvrage pendant 10 ans apr\u00e8s la r\u00e9ception des travaux.",
"Qualibat": "Qualibat est l\u2019organisme de r\u00e9f\u00e9rence pour la qualification des entreprises du b\u00e2timent. Gage de comp\u00e9tence et de s\u00e9rieux.",
"RGE": "Le label RGE (Reconnu Garant de l\u2019Environnement) vous permet de b\u00e9n\u00e9ficier des aides de l\u2019\u00c9tat : MaPrimeR\u00e9nov\u2019, CEE, \u00e9co-PTZ.",
};
return (
<>
<button
onClick={() => setOpen(true)}
className="flex items-center gap-2 bg-white/10 hover:bg-white/20 border border-white/20 rounded-full px-4 py-1.5 transition-colors cursor-pointer"
>
<svg className="w-4 h-4 text-green-400" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M9 12l2 2 4-4m5.618-4.016A11.955 11.955 0 0112 2.944a11.955 11.955 0 01-8.618 3.04A12.02 12.02 0 003 9c0 5.591 3.824 10.29 9 11.622 5.176-1.332 9-6.03 9-11.622 0-1.042-.133-2.052-.382-3.016z" />
</svg>
<span className="text-white text-xs font-semibold">{name}</span>
</button>
{/* Popup */}
{open && (
<div className="fixed inset-0 z-[100] flex items-center justify-center bg-black/50 p-4" onClick={() => setOpen(false)}>
<div className="bg-white rounded-2xl p-6 max-w-sm w-full shadow-2xl" onClick={(e) => e.stopPropagation()}>
<div className="flex items-center gap-3 mb-4">
<div className="w-10 h-10 bg-green-100 rounded-full flex items-center justify-center">
<svg className="w-5 h-5 text-green-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M9 12l2 2 4-4m5.618-4.016A11.955 11.955 0 0112 2.944a11.955 11.955 0 01-8.618 3.04A12.02 12.02 0 003 9c0 5.591 3.824 10.29 9 11.622 5.176-1.332 9-6.03 9-11.622 0-1.042-.133-2.052-.382-3.016z" />
</svg>
</div>
<h3 className="text-[#1b2a4a] font-bold text-lg">{name}</h3>
</div>
<p className="text-gray-600 text-sm leading-relaxed mb-5">
{infos[name] || "Certification professionnelle v\u00e9rifi\u00e9e."}
</p>
<button
onClick={() => setOpen(false)}
className="w-full bg-[#1b2a4a] text-white font-semibold text-sm py-2.5 rounded-xl hover:bg-[#1b2a4a]/90 transition-colors cursor-pointer"
>
Compris
</button>
</div>
</div>
)}
</>
);
}
function DevisForm() {
const [step, setStep] = useState<"type" | "details" | "urgence">("type");
const [projectType, setProjectType] = useState("");
if (step === "urgence") {
return (
<div className="bg-white rounded-2xl p-6 sm:p-8 text-center">
<div className="w-16 h-16 bg-red-100 rounded-full flex items-center justify-center mx-auto mb-4">
<svg className="w-8 h-8 text-red-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-2.5L13.732 4c-.77-.833-1.964-.833-2.732 0L4.082 16.5c-.77.833.192 2.5 1.732 2.5z" />
</svg>
</div>
<h3 className="text-[#1b2a4a] font-bold text-xl mb-2">Urgence d\u00e9tect\u00e9e !</h3>
<p className="text-gray-500 text-sm mb-6">Pour une intervention rapide, appelez directement le patron :</p>
<a
href="tel:+33604408157"
className="inline-flex items-center justify-center gap-3 bg-red-600 hover:bg-red-700 text-white font-bold text-lg px-8 py-4 rounded-xl transition-colors w-full"
>
<svg className="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M3 5a2 2 0 012-2h3.28a1 1 0 01.948.684l1.498 4.493a1 1 0 01-.502 1.21l-2.257 1.13a11.042 11.042 0 005.516 5.516l1.13-2.257a1 1 0 011.21-.502l4.493 1.498a1 1 0 01.684.949V19a2 2 0 01-2 2h-1C9.716 21 3 14.284 3 6V5z" />
</svg>
APPELER LE PATRON
</a>
<p className="text-gray-400 text-xs mt-3">Disponible 7j/7 pour les urgences</p>
<button onClick={() => setStep("type")} className="text-gray-400 hover:text-gray-600 text-sm mt-4 underline cursor-pointer">
&larr; Retour au formulaire
</button>
</div>
);
}
if (step === "details") {
return (
<div className="bg-white rounded-2xl p-6 sm:p-8">
<div className="flex items-center gap-2 mb-6">
<span className="bg-orange text-white text-xs font-bold px-2.5 py-1 rounded-full">2/2</span>
<h3 className="text-[#1b2a4a] font-bold text-lg">D\u00e9tails du projet</h3>
</div>
<p className="text-gray-400 text-sm mb-5">Type : <strong className="text-[#1b2a4a]">{projectType}</strong></p>
<div className="space-y-4">
<div>
<label className="block text-sm font-medium text-gray-700 mb-1.5">Surface approximative</label>
<select className="w-full px-4 py-3 bg-[#f8f6f3] border border-gray-200 rounded-xl text-gray-800 text-sm focus:border-orange focus:ring-1 focus:ring-orange outline-none">
<option>Moins de 50m\u00b2</option>
<option>50 \u00e0 100m\u00b2</option>
<option>100 \u00e0 200m\u00b2</option>
<option>Plus de 200m\u00b2</option>
</select>
</div>
<div>
<label className="block text-sm font-medium text-gray-700 mb-1.5">Votre nom</label>
<input type="text" placeholder="Marc Dupont" className="w-full px-4 py-3 bg-[#f8f6f3] border border-gray-200 rounded-xl text-gray-800 text-sm placeholder:text-gray-400 focus:border-orange focus:ring-1 focus:ring-orange outline-none" />
</div>
<div>
<label className="block text-sm font-medium text-gray-700 mb-1.5">T\u00e9l\u00e9phone</label>
<input type="tel" placeholder="06 12 34 56 78" className="w-full px-4 py-3 bg-[#f8f6f3] border border-gray-200 rounded-xl text-gray-800 text-sm placeholder:text-gray-400 focus:border-orange focus:ring-1 focus:ring-orange outline-none" />
</div>
<div>
<label className="block text-sm font-medium text-gray-700 mb-1.5">Ville</label>
<input type="text" placeholder="Douai, Orchies, Valenciennes..." className="w-full px-4 py-3 bg-[#f8f6f3] border border-gray-200 rounded-xl text-gray-800 text-sm placeholder:text-gray-400 focus:border-orange focus:ring-1 focus:ring-orange outline-none" />
</div>
<Button size="lg" className="w-full">Envoyer ma demande de devis</Button>
<button onClick={() => setStep("type")} className="w-full text-gray-400 hover:text-gray-600 text-sm underline cursor-pointer">
&larr; Retour
</button>
</div>
</div>
);
}
return (
<div className="bg-white rounded-2xl p-6 sm:p-8">
<div className="flex items-center gap-2 mb-6">
<span className="bg-orange text-white text-xs font-bold px-2.5 py-1 rounded-full">1/2</span>
<h3 className="text-[#1b2a4a] font-bold text-lg">Quel type de projet ?</h3>
</div>
<div className="grid grid-cols-1 sm:grid-cols-2 gap-3">
{[
{ label: "Urgence fuite / d\u00e9g\u00e2t", urgent: true },
{ label: "R\u00e9novation toiture", urgent: false },
{ label: "Ravalement fa\u00e7ade", urgent: false },
{ label: "Ma\u00e7onnerie neuve", urgent: false },
{ label: "Charpente / Isolation", urgent: false },
{ label: "Autre projet", urgent: false },
].map((item) => (
<button
key={item.label}
onClick={() => {
setProjectType(item.label);
if (item.urgent) {
setStep("urgence");
} else {
setStep("details");
}
}}
className={`p-4 rounded-xl border-2 text-left transition-all cursor-pointer hover:shadow-md ${
item.urgent
? "border-red-300 bg-red-50 hover:border-red-500"
: "border-gray-200 bg-[#f8f6f3] hover:border-orange"
}`}
>
<p className={`font-semibold text-sm ${item.urgent ? "text-red-600" : "text-[#1b2a4a]"}`}>
{item.urgent && "\u26a0\ufe0f "}{item.label}
</p>
</button>
))}
</div>
</div>
);
}

View File

@@ -1,148 +1,208 @@
import type { Metadata } from "next";
import Link from "next/link";
import Button from "@/components/ui/Button";
import MaconClient from "./MaconClient";
export const metadata: Metadata = {
title: "D\u00e9mo Site Ma\u00e7on / Couvreur - Pack Gros \u0152uvre",
title: "D\u00e9mo Site Ma\u00e7on / Couvreur - L'Expertise Solide | HookLab",
description:
"D\u00e9couvrez le mod\u00e8le de site HookLab pour ma\u00e7ons et couvreurs. Galerie Avant/Apr\u00e8s, bouton Urgence Fuite, optimis\u00e9 SEO local.",
"Mod\u00e8le de site HookLab pour ma\u00e7ons, couvreurs et charpentiers. Slider Avant/Apr\u00e8s interactif, badges garanties, formulaire intelligent, bouton urgence.",
};
const avantApres = [
{ avant: "Toiture v\u00e9tuste - Tuiles cass\u00e9es", apres: "R\u00e9fection compl\u00e8te en tuiles m\u00e9caniques" },
{ avant: "Fa\u00e7ade fissur\u00e9e - Enduit d\u00e9grad\u00e9", apres: "Ravalement complet + isolation" },
{ avant: "Chemin\u00e9e en ruine", apres: "Reconstruction + \u00e9tanch\u00e9it\u00e9" },
];
export default function MaconDemo() {
return (
<main className="min-h-screen bg-bg">
{/* Nav simplifi\u00e9e */}
<nav className="sticky top-0 z-50 bg-navy border-b border-white/10">
<main className="min-h-screen bg-[#f8f6f3]">
{/* Nav avec badge dispo */}
<nav className="sticky top-0 z-50 bg-[#1b2a4a] border-b border-white/10">
<div className="max-w-6xl mx-auto px-4 sm:px-6 lg:px-8 flex items-center justify-between h-16">
<div className="flex items-center gap-3">
<Link href="/" className="text-white/60 hover:text-white text-sm transition-colors">
&larr; Retour HookLab
&larr; HookLab
</Link>
<span className="text-white/30">|</span>
<span className="text-white font-bold text-sm">
D\u00e9mo : <span className="text-orange">Pack Gros \u0152uvre</span>
[Votre Entreprise] &mdash; <span className="text-orange">Ma\u00e7onnerie & Couverture</span>
</span>
</div>
<a
href="tel:+33600000000"
className="bg-red-600 hover:bg-red-700 text-white font-bold text-sm px-4 py-2 rounded-lg transition-colors flex items-center gap-2"
>
<svg className="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M3 5a2 2 0 012-2h3.28a1 1 0 01.948.684l1.498 4.493a1 1 0 01-.502 1.21l-2.257 1.13a11.042 11.042 0 005.516 5.516l1.13-2.257a1 1 0 011.21-.502l4.493 1.498a1 1 0 01.684.949V19a2 2 0 01-2 2h-1C9.716 21 3 14.284 3 6V5z" />
</svg>
Urgence Fuite
</a>
<div className="flex items-center gap-3">
{/* Badge dispo */}
<div className="hidden sm:flex items-center gap-2 bg-green-500/20 border border-green-500/30 rounded-full px-3 py-1">
<span className="w-2 h-2 bg-green-400 rounded-full animate-pulse" />
<span className="text-green-400 text-xs font-semibold">Dispo imm\u00e9diate</span>
</div>
<a
href="tel:+33604408157"
className="bg-red-600 hover:bg-red-700 text-white font-bold text-sm px-4 py-2 rounded-lg transition-colors flex items-center gap-2"
>
<svg className="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M3 5a2 2 0 012-2h3.28a1 1 0 01.948.684l1.498 4.493a1 1 0 01-.502 1.21l-2.257 1.13a11.042 11.042 0 005.516 5.516l1.13-2.257a1 1 0 011.21-.502l4.493 1.498a1 1 0 01.684.949V19a2 2 0 01-2 2h-1C9.716 21 3 14.284 3 6V5z" />
</svg>
<span className="hidden sm:inline">Urgence Fuite</span>
<span className="sm:hidden">Appeler</span>
</a>
</div>
</div>
</nav>
{/* Certifications en haut - immanquables */}
<div className="bg-[#1b2a4a] border-b border-white/5">
<div className="max-w-6xl mx-auto px-4 py-3 flex flex-wrap items-center justify-center gap-4 sm:gap-8">
{["D\u00e9cennale", "Qualibat", "RGE"].map((cert) => (
<MaconClient key={cert} certName={cert} />
))}
</div>
</div>
{/* Hero */}
<section className="py-20 md:py-28 bg-navy text-center">
<section className="py-20 md:py-28 bg-[#1b2a4a] text-center">
<div className="max-w-4xl mx-auto px-4">
<span className="inline-block px-3 py-1.5 bg-orange/20 border border-orange/30 rounded-full text-orange text-xs font-semibold mb-6">
Ma\u00e7onnerie & Couverture
Ma\u00e7onnerie &middot; Couverture &middot; Charpente
</span>
<h1 className="text-3xl sm:text-4xl md:text-5xl font-extrabold text-white leading-tight mb-6">
[Votre Entreprise] &mdash; Ma\u00e7on Couvreur <span className="text-orange">dans le Nord</span>
<h1 className="text-3xl sm:text-4xl md:text-5xl font-extrabold text-white leading-tight mb-4">
Vos chantiers parlent pour vous.{" "}
<span className="text-orange">Votre site aussi.</span>
</h1>
<p className="text-white/60 text-lg max-w-2xl mx-auto mb-8">
Plus de 15 ans d&rsquo;exp\u00e9rience en ma\u00e7onnerie et couverture. Devis gratuit sous 24h.
Intervention rapide sur Douai, Orchies et Valenciennes.
<p className="text-white/60 text-lg max-w-2xl mx-auto mb-4">
Dans le gros \u0153uvre, le client a peur. Peur que \u00e7a s&rsquo;\u00e9croule, peur des fuites,
peur que vous partiez avec l&rsquo;acompte. Ce site est une machine \u00e0 tuer les objections.
</p>
<p className="text-white/40 text-sm mb-8">
Intervention rapide sur Douai, Orchies, Valenciennes et environs.
</p>
<div className="flex flex-col sm:flex-row gap-4 justify-center">
<Button size="lg" className="pulse-glow">
Demander un Devis Gratuit
</Button>
<a href="#devis">
<Button size="lg" className="w-full sm:w-auto pulse-glow">
Demander un Devis Toiture
</Button>
</a>
<a
href="tel:+33600000000"
href="tel:+33604408157"
className="inline-flex items-center justify-center gap-2 bg-red-600 hover:bg-red-700 text-white font-bold px-6 py-3 rounded-xl transition-colors"
>
<svg className="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M3 5a2 2 0 012-2h3.28a1 1 0 01.948.684l1.498 4.493a1 1 0 01-.502 1.21l-2.257 1.13a11.042 11.042 0 005.516 5.516l1.13-2.257a1 1 0 011.21-.502l4.493 1.498a1 1 0 01.684.949V19a2 2 0 01-2 2h-1C9.716 21 3 14.284 3 6V5z" />
</svg>
Urgence Fuite : Appeler Maintenant
APPELER LE PATRON
</a>
</div>
</div>
</section>
{/* Avant / Apr\u00e8s */}
<section className="py-16 md:py-24 bg-bg-white">
{/* Slider Magic Reveal - Avant/Apr\u00e8s */}
<section className="py-16 md:py-24 bg-white">
<div className="max-w-6xl mx-auto px-4 sm:px-6 lg:px-8">
<div className="text-center mb-12">
<h2 className="text-2xl md:text-3xl font-bold text-navy mb-3">
Galerie <span className="text-orange">Avant / Apr\u00e8s</span>
<h2 className="text-2xl md:text-3xl font-bold text-[#1b2a4a] mb-3">
La preuve par l&rsquo;image &mdash; <span className="text-orange">Avant / Apr\u00e8s</span>
</h2>
<p className="text-text-light">La preuve par l&rsquo;image. Nos chantiers parlent d&rsquo;eux-m\u00eames.</p>
<p className="text-gray-500">Glissez la barre pour voir la transformation. Impact visuel imm\u00e9diat.</p>
</div>
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
{[
{ avant: "Toiture v\u00e9tuste \u2014 Tuiles cass\u00e9es, infiltrations", apres: "R\u00e9fection compl\u00e8te en tuiles m\u00e9caniques" },
{ avant: "Fa\u00e7ade fissur\u00e9e \u2014 Enduit d\u00e9grad\u00e9", apres: "Ravalement complet + isolation thermique" },
{ avant: "Chemin\u00e9e en ruine \u2014 Danger effondrement", apres: "Reconstruction + \u00e9tanch\u00e9it\u00e9 garantie" },
].map((item, i) => (
<MaconClient key={i} type="slider" avantLabel={item.avant} apresLabel={item.apres} />
))}
</div>
</div>
</section>
{/* Garanties */}
<section className="py-16 md:py-24 bg-[#f8f6f3]">
<div className="max-w-4xl mx-auto px-4 sm:px-6 lg:px-8">
<div className="text-center mb-12">
<h2 className="text-2xl md:text-3xl font-bold text-[#1b2a4a] mb-3">
Vos <span className="text-orange">garanties</span>
</h2>
<p className="text-gray-500">Des certifications qui prot\u00e8gent votre investissement.</p>
</div>
<div className="grid grid-cols-1 md:grid-cols-3 gap-6">
{avantApres.map((item, i) => (
<div key={i} className="bg-bg border border-border rounded-2xl overflow-hidden">
<div className="grid grid-cols-2">
<div className="h-40 bg-red-50 flex items-center justify-center border-r border-border">
<div className="text-center p-3">
<p className="text-red-500 text-xs font-bold uppercase mb-1">Avant</p>
<p className="text-text-muted text-xs">{item.avant}</p>
</div>
</div>
<div className="h-40 bg-green-50 flex items-center justify-center">
<div className="text-center p-3">
<p className="text-green-600 text-xs font-bold uppercase mb-1">Apr\u00e8s</p>
<p className="text-text-muted text-xs">{item.apres}</p>
</div>
</div>
</div>
{[
{
name: "Garantie D\u00e9cennale",
desc: "Votre ouvrage est couvert pendant 10 ans. En cas de d\u00e9faut structurel, les r\u00e9parations sont prises en charge int\u00e9gralement.",
icon: "\ud83d\udee1\ufe0f",
},
{
name: "Qualibat RGE",
desc: "Cette certification vous garantit des aides de l\u2019\u00c9tat (MaPrimeR\u00e9nov\u2019, CEE). Jusqu\u2019\u00e0 90% de vos travaux financ\u00e9s.",
icon: "\u2705",
},
{
name: "Assurance Responsabilit\u00e9",
desc: "Chaque chantier est assur\u00e9. Vous ne prenez aucun risque financier, m\u00eame en cas d\u2019impr\u00e9vu.",
icon: "\ud83d\udcbc",
},
].map((g, i) => (
<div key={i} className="bg-white border border-gray-200 rounded-2xl p-6 text-center hover:shadow-md transition-shadow">
<div className="text-4xl mb-4">{g.icon}</div>
<h3 className="text-[#1b2a4a] font-bold text-lg mb-2">{g.name}</h3>
<p className="text-gray-500 text-sm leading-relaxed">{g.desc}</p>
</div>
))}
</div>
</div>
</section>
{/* Avis */}
<section className="py-16 md:py-24 bg-bg">
{/* Avis clients */}
<section className="py-16 md:py-24 bg-white">
<div className="max-w-4xl mx-auto px-4 text-center">
<h2 className="text-2xl md:text-3xl font-bold text-navy mb-10">
<h2 className="text-2xl md:text-3xl font-bold text-[#1b2a4a] mb-10">
Ce que disent <span className="text-orange">nos clients</span>
</h2>
<div className="grid grid-cols-1 md:grid-cols-2 gap-6">
{[
{ name: "Marc D.", ville: "Douai", text: "Toiture refaite en 3 jours. Propre, ponctuel, prix respect\u00e9. Je recommande \u00e0 100%." },
{ name: "Sophie L.", ville: "Orchies", text: "Fuite d\u2019urgence un dimanche. Ils sont venus en 2h. Travail impeccable." },
{ name: "Marc D.", ville: "Douai", text: "Toiture refaite en 3 jours. Propre, ponctuel, prix respect\u00e9. Je recommande \u00e0 100%.", note: 5 },
{ name: "Sophie L.", ville: "Orchies", text: "Fuite d\u2019urgence un dimanche. Ils sont venus en 2h. Travail impeccable et prix honn\u00eate.", note: 5 },
{ name: "Patrick M.", ville: "Valenciennes", text: "Ravalement fa\u00e7ade complet. R\u00e9sultat magnifique, les voisins nous demandent le contact !", note: 5 },
{ name: "Isabelle R.", ville: "Arleux", text: "Charpente trait\u00e9e et renforc\u00e9e. \u00c9quipe s\u00e9rieuse, devis respect\u00e9 au centime pr\u00e8s.", note: 5 },
].map((avis, i) => (
<div key={i} className="bg-bg-white border border-border rounded-xl p-6 text-left">
<div key={i} className="bg-[#f8f6f3] border border-gray-200 rounded-xl p-6 text-left">
<div className="flex gap-1 mb-3">
{[...Array(5)].map((_, j) => (
{[...Array(avis.note)].map((_, j) => (
<svg key={j} className="w-4 h-4 text-orange" fill="currentColor" viewBox="0 0 24 24">
<path d="M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z" />
</svg>
))}
</div>
<p className="text-text-light text-sm leading-relaxed mb-3">&ldquo;{avis.text}&rdquo;</p>
<p className="text-navy font-semibold text-sm">{avis.name} &mdash; <span className="text-text-muted font-normal">{avis.ville}</span></p>
<p className="text-gray-600 text-sm leading-relaxed mb-3">&ldquo;{avis.text}&rdquo;</p>
<p className="text-[#1b2a4a] font-semibold text-sm">{avis.name} &mdash; <span className="text-gray-400 font-normal">{avis.ville}</span></p>
</div>
))}
</div>
</div>
</section>
{/* CTA */}
<section className="py-16 bg-navy text-center">
{/* Formulaire intelligent */}
<section id="devis" className="py-16 md:py-24 bg-[#1b2a4a]">
<div className="max-w-2xl mx-auto px-4">
<p className="text-orange text-xs font-semibold uppercase tracking-wider mb-3">Ceci est une d\u00e9mo HookLab</p>
<div className="text-center mb-10">
<h2 className="text-2xl md:text-3xl font-bold text-white mb-3">
Demander un <span className="text-orange">devis gratuit</span>
</h2>
<p className="text-white/60">Formulaire intelligent : on filtre pour ne recevoir que les vrais projets.</p>
</div>
<MaconClient type="form" />
</div>
</section>
{/* CTA HookLab */}
<section className="py-16 bg-orange text-center">
<div className="max-w-2xl mx-auto px-4">
<p className="text-white/80 text-xs font-semibold uppercase tracking-wider mb-3">Ceci est une d\u00e9mo HookLab</p>
<h2 className="text-2xl md:text-3xl font-bold text-white mb-4">
Vous voulez le m\u00eame site pour votre entreprise&nbsp;?
Vous voulez le m\u00eame site pour votre entreprise ?
</h2>
<p className="text-white/60 mb-6">
Imaginez votre logo, vos photos et votre num\u00e9ro \u00e0 la place. C&rsquo;est exactement ce que je construis pour vous.
<p className="text-white/80 mb-6">
Imaginez votre logo, vos photos de chantier et votre num\u00e9ro \u00e0 la place. C&rsquo;est exactement ce que je construis pour vous.
</p>
<Link href="/#contact">
<Button size="lg" className="pulse-glow">
<Button size="lg" className="bg-[#1b2a4a] hover:bg-[#1b2a4a]/90 border-[#1b2a4a]">
Demander Mon Audit Gratuit
</Button>
</Link>

View File

@@ -0,0 +1,105 @@
"use client";
import { useState } from "react";
interface Realisation {
titre: string;
type: string;
lieu: string;
saison: string;
}
interface PaysagisteClientProps {
realisations?: Realisation[];
whatsapp?: boolean;
}
export default function PaysagisteClient({ realisations, whatsapp }: PaysagisteClientProps) {
if (whatsapp) {
return <WhatsAppButton />;
}
if (realisations) {
return <GalerieFiltrable realisations={realisations} />;
}
return null;
}
function WhatsAppButton() {
return (
<a
href="https://wa.me/33604408157?text=Bonjour%2C%20je%20souhaite%20un%20devis%20pour%20mon%20jardin"
target="_blank"
rel="noopener noreferrer"
className="fixed bottom-6 right-6 z-50 bg-[#25D366] hover:bg-[#1fb855] text-white rounded-full p-4 shadow-lg hover:shadow-xl transition-all group"
aria-label="Contacter sur WhatsApp"
>
<svg className="w-7 h-7" fill="currentColor" viewBox="0 0 24 24">
<path d="M17.472 14.382c-.297-.149-1.758-.867-2.03-.967-.273-.099-.471-.148-.67.15-.197.297-.767.966-.94 1.164-.173.199-.347.223-.644.075-.297-.15-1.255-.463-2.39-1.475-.883-.788-1.48-1.761-1.653-2.059-.173-.297-.018-.458.13-.606.134-.133.298-.347.446-.52.149-.174.198-.298.298-.497.099-.198.05-.371-.025-.52-.075-.149-.669-1.612-.916-2.207-.242-.579-.487-.5-.669-.51-.173-.008-.371-.01-.57-.01-.198 0-.52.074-.792.372-.272.297-1.04 1.016-1.04 2.479 0 1.462 1.065 2.875 1.213 3.074.149.198 2.096 3.2 5.077 4.487.709.306 1.262.489 1.694.625.712.227 1.36.195 1.871.118.571-.085 1.758-.719 2.006-1.413.248-.694.248-1.289.173-1.413-.074-.124-.272-.198-.57-.347m-5.421 7.403h-.004a9.87 9.87 0 01-5.031-1.378l-.361-.214-3.741.982.998-3.648-.235-.374a9.86 9.86 0 01-1.51-5.26c.001-5.45 4.436-9.884 9.888-9.884 2.64 0 5.122 1.03 6.988 2.898a9.825 9.825 0 012.893 6.994c-.003 5.45-4.437 9.884-9.885 9.884m8.413-18.297A11.815 11.815 0 0012.05 0C5.495 0 .16 5.335.157 11.892c0 2.096.547 4.142 1.588 5.945L.057 24l6.305-1.654a11.882 11.882 0 005.683 1.448h.005c6.554 0 11.89-5.335 11.893-11.893a11.821 11.821 0 00-3.48-8.413z" />
</svg>
<span className="absolute -top-2 -left-2 bg-white text-gray-800 text-[10px] font-bold px-2 py-0.5 rounded-full shadow-md opacity-0 group-hover:opacity-100 transition-opacity whitespace-nowrap">
Je veux le m\u00eame jardin !
</span>
</a>
);
}
function GalerieFiltrable({ realisations }: { realisations: Realisation[] }) {
const [filter, setFilter] = useState("Tous");
const types = ["Tous", "Terrasses", "Plantations", "All\u00e9es", "Entretien"];
const filtered = filter === "Tous" ? realisations : realisations.filter((r) => r.type === filter);
return (
<>
{/* Filtres */}
<div className="flex flex-wrap justify-center gap-2 mb-8">
{types.map((t) => (
<button
key={t}
onClick={() => setFilter(t)}
className={`px-4 py-2 text-sm font-semibold rounded-full transition-colors cursor-pointer ${
filter === t
? "bg-green-600 text-white"
: "bg-gray-100 text-gray-500 hover:bg-gray-200"
}`}
>
{t}
</button>
))}
</div>
{/* Grille */}
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-5">
{filtered.map((r, i) => (
<div key={i} className="bg-[#f0f5ed] border border-gray-100 rounded-2xl overflow-hidden group hover:shadow-lg transition-shadow">
<div className="h-48 bg-gradient-to-br from-green-100 to-green-50 flex items-center justify-center relative overflow-hidden">
<div className="text-center">
<svg className="w-12 h-12 text-green-300 mx-auto mb-2 group-hover:scale-110 transition-transform" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={1} d="M5 3v4M3 5h4M6 17v4m-2-2h4m5-16l2.286 6.857L21 12l-5.714 2.143L13 21l-2.286-6.857L5 12l5.714-2.143L13 3z" />
</svg>
<p className="text-gray-400 text-xs">Photo HD du projet</p>
</div>
{/* Tag type */}
<span className={`absolute top-3 left-3 text-[10px] font-bold px-2 py-0.5 rounded-full ${
r.type === "Entretien" ? "bg-amber-100 text-amber-700" : "bg-green-100 text-green-700"
}`}>
{r.type}
</span>
</div>
<div className="p-4">
<h3 className="text-gray-800 font-bold text-sm mb-1">{r.titre}</h3>
<p className="text-gray-400 text-xs flex items-center gap-1">
<svg className="w-3 h-3" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M17.657 16.657L13.414 20.9a1.998 1.998 0 01-2.827 0l-4.244-4.243a8 8 0 1111.314 0z" />
</svg>
{r.lieu}
</p>
</div>
</div>
))}
</div>
</>
);
}

View File

@@ -1,129 +1,187 @@
import type { Metadata } from "next";
import Link from "next/link";
import Button from "@/components/ui/Button";
import PaysagisteClient from "./PaysagisteClient";
export const metadata: Metadata = {
title: "D\u00e9mo Site Paysagiste / Peintre - Pack Esth\u00e9tique",
title: "D\u00e9mo Site Paysagiste / Peintre - L'Artisan Cr\u00e9ateur | HookLab",
description:
"D\u00e9couvrez le mod\u00e8le de site HookLab pour paysagistes et peintres. Design \u00e9pur\u00e9, galerie photo immersive, filtrage Cr\u00e9ation vs Entretien.",
"Mod\u00e8le de site HookLab pour paysagistes, peintres et d\u00e9corateurs. Galerie filtrable, saisonnalit\u00e9 intelligente, bouton WhatsApp flottant.",
};
const realisations = [
{ titre: "Jardin contemporain", type: "Cr\u00e9ation", lieu: "Douai" },
{ titre: "Terrasse bois & pergola", type: "Cr\u00e9ation", lieu: "Orchies" },
{ titre: "Entretien parc 2000m\u00b2", type: "Entretien", lieu: "Valenciennes" },
{ titre: "Am\u00e9nagement piscine", type: "Cr\u00e9ation", lieu: "Arleux" },
{ titre: "Taille de haies & \u00e9lagage", type: "Entretien", lieu: "Flines-lez-Raches" },
{ titre: "Jardin japonais", type: "Cr\u00e9ation", lieu: "Saint-Amand" },
{ titre: "Jardin contemporain avec terrasse composite", type: "Terrasses", lieu: "Orchies", saison: "printemps" },
{ titre: "Am\u00e9nagement complet piscine + cl\u00f4ture", type: "Terrasses", lieu: "Douai", saison: "printemps" },
{ titre: "Cr\u00e9ation massif fleuri 4 saisons", type: "Plantations", lieu: "Valenciennes", saison: "printemps" },
{ titre: "Haie brise-vue naturelle en bambou", type: "Plantations", lieu: "Arleux", saison: "automne" },
{ titre: "All\u00e9e carrossable en pav\u00e9s anciens", type: "All\u00e9es", lieu: "Saint-Amand", saison: "automne" },
{ titre: "Jardin japonais zen avec bassin", type: "Plantations", lieu: "Flines-lez-Raches", saison: "printemps" },
{ titre: "Taille architecturale haies buis", type: "Entretien", lieu: "Denain", saison: "automne" },
{ titre: "Entretien annuel parc 3000m\u00b2", type: "Entretien", lieu: "Douai", saison: "automne" },
];
export default function PaysagisteDemo() {
const currentMonth = new Date().getMonth();
const isSpringSummer = currentMonth >= 2 && currentMonth <= 8;
return (
<main className="min-h-screen bg-bg">
{/* Nav simplifi\u00e9e */}
<nav className="sticky top-0 z-50 bg-bg-white/90 backdrop-blur-md border-b border-border">
<main className="min-h-screen bg-white">
{/* Nav \u00e9pur\u00e9e */}
<nav className="sticky top-0 z-50 bg-white/90 backdrop-blur-md border-b border-gray-100">
<div className="max-w-6xl mx-auto px-4 sm:px-6 lg:px-8 flex items-center justify-between h-16">
<div className="flex items-center gap-3">
<Link href="/" className="text-text-muted hover:text-navy text-sm transition-colors">
&larr; Retour HookLab
<Link href="/" className="text-gray-400 hover:text-gray-700 text-sm transition-colors">
&larr; HookLab
</Link>
<span className="text-border">|</span>
<span className="text-navy font-bold text-sm">
D\u00e9mo : <span className="text-orange">Pack Esth\u00e9tique</span>
<span className="text-gray-200">|</span>
<span className="text-gray-800 font-bold text-sm">
[Votre Entreprise] &mdash; <span className="text-green-600">Paysagiste</span>
</span>
</div>
<a
href="tel:+33600000000"
className="bg-orange hover:bg-orange/90 text-white font-bold text-sm px-4 py-2 rounded-lg transition-colors"
href="tel:+33604408157"
className="bg-green-600 hover:bg-green-700 text-white font-bold text-sm px-5 py-2 rounded-lg transition-colors"
>
Devis Gratuit
</a>
</div>
</nav>
{/* Banni\u00e8re saisonni\u00e8re */}
<div className={`text-center py-2 text-xs font-semibold ${isSpringSummer ? "bg-green-50 text-green-700" : "bg-amber-50 text-amber-700"}`}>
{isSpringSummer
? "C\u2019est la saison ! Cr\u00e9ation de terrasses & plantations \u2014 Demandez votre devis maintenant"
: "Pr\u00e9parez le printemps ! Taille, \u00e9lagage & entretien d\u2019automne \u2014 Planifiez vos travaux"
}
</div>
{/* Hero \u00e9pur\u00e9 */}
<section className="py-24 md:py-36 bg-[#1a2e1a] text-center relative overflow-hidden">
<div className="absolute inset-0 bg-[radial-gradient(circle_at_50%_80%,rgba(34,139,34,0.15),transparent_70%)]" />
<section className="py-24 md:py-36 bg-[#f0f5ed] text-center relative overflow-hidden">
<div className="absolute inset-0 bg-[radial-gradient(circle_at_50%_80%,rgba(34,139,34,0.08),transparent_70%)]" />
<div className="relative max-w-4xl mx-auto px-4">
<span className="inline-block px-3 py-1.5 bg-green-500/20 border border-green-500/30 rounded-full text-green-400 text-xs font-semibold mb-6">
Paysagisme & Espaces Verts
<span className="inline-block px-3 py-1.5 bg-green-100 border border-green-200 rounded-full text-green-700 text-xs font-semibold mb-6">
Paysagisme &middot; Espaces Verts &middot; D\u00e9coration
</span>
<h1 className="text-3xl sm:text-4xl md:text-5xl font-extrabold text-white leading-tight mb-6">
[Votre Entreprise] &mdash; Paysagiste <span className="text-green-400">dans le Nord</span>
<h1 className="text-3xl sm:text-4xl md:text-5xl font-extrabold text-gray-900 leading-tight mb-4">
Ne vendez pas des travaux,{" "}
<span className="text-green-600">vendez du r\u00eave.</span>
</h1>
<p className="text-white/60 text-lg max-w-2xl mx-auto mb-8">
Cr\u00e9ation de jardins d&rsquo;exception et entretien d&rsquo;espaces verts.
La nature est notre m\u00e9tier, la beaut\u00e9 notre signature.
<p className="text-gray-500 text-lg max-w-2xl mx-auto mb-4">
Pour un jardin ou un int\u00e9rieur, votre client n&rsquo;ach\u00e8te pas de la technique,
il ach\u00e8te une &laquo;&nbsp;ambiance&nbsp;&raquo;. Ce site est votre galerie d&rsquo;art.
</p>
<p className="text-gray-400 text-sm mb-8">
Cr\u00e9ations &agrave; Douai, Orchies, Valenciennes, Saint-Amand et environs.
</p>
<div className="flex flex-col sm:flex-row gap-4 justify-center">
<Button size="lg" className="bg-green-600 hover:bg-green-700 border-green-600">
Demander un Devis Cr\u00e9ation
</Button>
<Button size="lg" variant="outline" className="border-white/30 text-white hover:bg-white/10">
Devis Entretien
</Button>
<a href="#devis">
<Button size="lg" className="bg-green-600 hover:bg-green-700 border-green-600">
Demander un Devis Cr\u00e9ation
</Button>
</a>
<a href="#devis">
<Button size="lg" variant="outline" className="border-green-300 text-green-700 hover:bg-green-50">
Devis Entretien
</Button>
</a>
</div>
</div>
</section>
{/* R\u00e9alisations avec filtrage */}
<section className="py-16 md:py-24 bg-bg-white">
{/* R\u00e9alisations filtrables */}
<section className="py-16 md:py-24 bg-white">
<div className="max-w-6xl mx-auto px-4 sm:px-6 lg:px-8">
<div className="text-center mb-12">
<h2 className="text-2xl md:text-3xl font-bold text-navy mb-3">
Nos <span className="text-orange">r\u00e9alisations</span>
<h2 className="text-2xl md:text-3xl font-bold text-gray-900 mb-3">
Nos <span className="text-green-600">r\u00e9alisations</span>
</h2>
<p className="text-text-light mb-6">
Filtrez par type de projet pour trouver l&rsquo;inspiration.
<p className="text-gray-500 mb-2">
Des cr\u00e9ations dans des lieux que vous connaissez. Projetez-vous.
</p>
{/* Filtre visuel (d\u00e9mo statique) */}
<div className="flex justify-center gap-3">
<span className="px-4 py-2 bg-navy text-white text-sm font-semibold rounded-full">Tous</span>
<span className="px-4 py-2 bg-bg border border-border text-text-light text-sm rounded-full cursor-pointer hover:border-navy transition-colors">Cr\u00e9ation</span>
<span className="px-4 py-2 bg-bg border border-border text-text-light text-sm rounded-full cursor-pointer hover:border-navy transition-colors">Entretien</span>
</div>
</div>
<PaysagisteClient realisations={realisations} />
</div>
</section>
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-6">
{realisations.map((r, i) => (
<div key={i} className="bg-bg border border-border rounded-2xl overflow-hidden group">
<div className="h-48 bg-green-50 flex items-center justify-center">
<div className="text-center">
<svg className="w-12 h-12 text-green-300 mx-auto mb-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={1} d="M5 3v4M3 5h4M6 17v4m-2-2h4m5-16l2.286 6.857L21 12l-5.714 2.143L13 21l-2.286-6.857L5 12l5.714-2.143L13 3z" />
</svg>
<p className="text-text-muted text-xs">Photo du projet</p>
</div>
</div>
<div className="p-4">
<div className="flex items-center justify-between mb-2">
<h3 className="text-navy font-bold text-sm">{r.titre}</h3>
<span className={`text-xs font-semibold px-2 py-0.5 rounded-full ${
r.type === "Cr\u00e9ation" ? "bg-green-100 text-green-700" : "bg-blue-100 text-blue-700"
}`}>
{r.type}
</span>
</div>
<p className="text-text-muted text-xs">{r.lieu}</p>
{/* Immersion locale */}
<section className="py-16 md:py-24 bg-[#f0f5ed]">
<div className="max-w-4xl mx-auto px-4 sm:px-6 lg:px-8 text-center">
<h2 className="text-2xl md:text-3xl font-bold text-gray-900 mb-10">
Des jardins pr\u00e8s de <span className="text-green-600">chez vous</span>
</h2>
<div className="grid grid-cols-2 md:grid-cols-3 gap-4">
{["Douai", "Orchies", "Valenciennes", "Arleux", "Saint-Amand", "Denain"].map((ville) => (
<div key={ville} className="bg-white rounded-xl p-4 border border-gray-100 hover:shadow-md transition-shadow">
<div className="w-10 h-10 bg-green-100 rounded-full flex items-center justify-center mx-auto mb-2">
<svg className="w-5 h-5 text-green-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M17.657 16.657L13.414 20.9a1.998 1.998 0 01-2.827 0l-4.244-4.243a8 8 0 1111.314 0z" />
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M15 11a3 3 0 11-6 0 3 3 0 016 0z" />
</svg>
</div>
<p className="text-gray-800 font-semibold text-sm">Jardin \u00e0 {ville}</p>
</div>
))}
</div>
</div>
</section>
{/* CTA */}
<section className="py-16 bg-[#1a2e1a] text-center">
{/* Formulaire */}
<section id="devis" className="py-16 md:py-24 bg-gray-900">
<div className="max-w-2xl mx-auto px-4">
<p className="text-orange text-xs font-semibold uppercase tracking-wider mb-3">Ceci est une d\u00e9mo HookLab</p>
<div className="text-center mb-10">
<h2 className="text-2xl md:text-3xl font-bold text-white mb-3">
Demander un <span className="text-green-400">devis gratuit</span>
</h2>
<p className="text-white/60">D\u00e9crivez votre projet, on vous recontacte sous 24h.</p>
</div>
<div className="bg-white rounded-2xl p-6 sm:p-8">
<div className="space-y-4">
<div>
<label className="block text-sm font-medium text-gray-700 mb-1.5">Type de projet</label>
<select className="w-full px-4 py-3 bg-gray-50 border border-gray-200 rounded-xl text-gray-800 text-sm focus:border-green-500 focus:ring-1 focus:ring-green-500 outline-none">
<option>Cr\u00e9ation de jardin complet</option>
<option>Terrasse / Am\u00e9nagement</option>
<option>Plantation / Massifs</option>
<option>Entretien r\u00e9gulier</option>
<option>Taille / \u00c9lagage</option>
<option>Cl\u00f4ture / Brise-vue</option>
</select>
</div>
<div>
<label className="block text-sm font-medium text-gray-700 mb-1.5">Votre nom</label>
<input type="text" placeholder="Votre nom" className="w-full px-4 py-3 bg-gray-50 border border-gray-200 rounded-xl text-gray-800 text-sm placeholder:text-gray-400 focus:border-green-500 focus:ring-1 focus:ring-green-500 outline-none" />
</div>
<div>
<label className="block text-sm font-medium text-gray-700 mb-1.5">T\u00e9l\u00e9phone</label>
<input type="tel" placeholder="06 12 34 56 78" className="w-full px-4 py-3 bg-gray-50 border border-gray-200 rounded-xl text-gray-800 text-sm placeholder:text-gray-400 focus:border-green-500 focus:ring-1 focus:ring-green-500 outline-none" />
</div>
<div>
<label className="block text-sm font-medium text-gray-700 mb-1.5">D\u00e9crivez votre projet</label>
<textarea rows={3} placeholder="Surface, style souhait\u00e9, budget approximatif..." className="w-full px-4 py-3 bg-gray-50 border border-gray-200 rounded-xl text-gray-800 text-sm placeholder:text-gray-400 focus:border-green-500 focus:ring-1 focus:ring-green-500 outline-none resize-none" />
</div>
<Button size="lg" className="w-full bg-green-600 hover:bg-green-700 border-green-600">
Envoyer ma demande
</Button>
</div>
</div>
</div>
</section>
{/* WhatsApp flottant */}
<PaysagisteClient whatsapp />
{/* CTA HookLab */}
<section className="py-16 bg-green-600 text-center">
<div className="max-w-2xl mx-auto px-4">
<p className="text-white/80 text-xs font-semibold uppercase tracking-wider mb-3">Ceci est une d\u00e9mo HookLab</p>
<h2 className="text-2xl md:text-3xl font-bold text-white mb-4">
Ce design vous pla\u00eet&nbsp;? Il peut &ecirc;tre &agrave; vous.
Ce design vous pla\u00eet ? Il peut \u00eatre \u00e0 vous.
</h2>
<p className="text-white/60 mb-6">
<p className="text-white/80 mb-6">
Imaginez vos plus beaux jardins mis en valeur comme \u00e7a. C&rsquo;est ce que je cr\u00e9e pour les paysagistes du Nord.
</p>
<Link href="/#contact">
<Button size="lg" className="bg-green-600 hover:bg-green-700 border-green-600">
<Button size="lg" className="bg-gray-900 hover:bg-gray-800 border-gray-900">
Demander Mon Audit Gratuit
</Button>
</Link>

View File

@@ -0,0 +1,189 @@
"use client";
import { useState } from "react";
import Button from "@/components/ui/Button";
interface PlombierClientProps {
type: "diagnostic" | "sticky";
}
export default function PlombierClient({ type }: PlombierClientProps) {
if (type === "sticky") return <StickyCall />;
if (type === "diagnostic") return <Diagnostic />;
return null;
}
function StickyCall() {
return (
<div className="fixed bottom-0 left-0 right-0 z-50 md:hidden bg-[#0a1628] border-t border-white/10 p-3 safe-area-bottom">
<a
href="tel:+33604408157"
className="flex items-center justify-center gap-3 bg-[#3b82f6] hover:bg-[#2563eb] text-white font-bold text-base py-3.5 rounded-xl w-full transition-colors"
>
<svg className="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M3 5a2 2 0 012-2h3.28a1 1 0 01.948.684l1.498 4.493a1 1 0 01-.502 1.21l-2.257 1.13a11.042 11.042 0 005.516 5.516l1.13-2.257a1 1 0 011.21-.502l4.493 1.498a1 1 0 01.684.949V19a2 2 0 01-2 2h-1C9.716 21 3 14.284 3 6V5z" />
</svg>
Appeler maintenant &mdash; 06 04 40 81 57
</a>
<p className="text-white/40 text-[10px] text-center mt-1">Devis gratuit &middot; Pas de surprise</p>
</div>
);
}
function Diagnostic() {
const [step, setStep] = useState(0);
const [answers, setAnswers] = useState<string[]>([]);
const questions = [
{
question: "Quel est le probl\u00e8me ?",
options: [
{ icon: "\ud83d\udca7", label: "Fuite d\u2019eau" },
{ icon: "\ud83d\udebd", label: "Canalisation bouch\u00e9e" },
{ icon: "\ud83d\udd25", label: "Panne chauffe-eau" },
{ icon: "\ud83d\udee0\ufe0f", label: "Autre probl\u00e8me" },
],
},
{
question: "Quel niveau d\u2019urgence ?",
options: [
{ icon: "\ud83d\udea8", label: "Urgent (fuite active)" },
{ icon: "\u23f0", label: "Sous 48h" },
{ icon: "\ud83d\udcc5", label: "Travaux planifi\u00e9s" },
],
},
{
question: "O\u00f9 \u00eates-vous situ\u00e9 ?",
options: [
{ icon: "\ud83d\udccd", label: "Douai / Environs" },
{ icon: "\ud83d\udccd", label: "Orchies / Environs" },
{ icon: "\ud83d\udccd", label: "Valenciennes / Environs" },
{ icon: "\ud83d\udccd", label: "Autre secteur" },
],
},
];
if (step >= questions.length) {
const isUrgent = answers[1]?.includes("Urgent");
const isOutOfZone = answers[2]?.includes("Autre");
if (isOutOfZone) {
return (
<div className="bg-white rounded-2xl p-6 sm:p-8 text-center">
<div className="w-16 h-16 bg-amber-100 rounded-full flex items-center justify-center mx-auto mb-4">
<span className="text-3xl">\ud83d\udccd</span>
</div>
<h3 className="text-gray-900 font-bold text-xl mb-2">Vous \u00eates hors de notre zone principale</h3>
<p className="text-gray-500 text-sm mb-6">
Notre rayon d&rsquo;action est Douai + 25km. Appelez-nous quand m\u00eame,
on trouvera peut-\u00eatre une solution !
</p>
<a
href="tel:+33604408157"
className="inline-flex items-center justify-center gap-2 bg-[#3b82f6] hover:bg-[#2563eb] text-white font-bold px-6 py-3 rounded-xl transition-colors"
>
Appeler quand m\u00eame
</a>
<button onClick={() => { setStep(0); setAnswers([]); }} className="block mx-auto mt-4 text-gray-400 hover:text-gray-600 text-sm underline cursor-pointer">
Recommencer le diagnostic
</button>
</div>
);
}
if (isUrgent) {
return (
<div className="bg-white rounded-2xl p-6 sm:p-8 text-center">
<div className="w-16 h-16 bg-red-100 rounded-full flex items-center justify-center mx-auto mb-4 animate-pulse">
<span className="text-3xl">\ud83d\udea8</span>
</div>
<h3 className="text-gray-900 font-bold text-xl mb-2">Urgence d\u00e9tect\u00e9e !</h3>
<p className="text-gray-500 text-sm mb-2">
<strong>{answers[0]}</strong> &mdash; {answers[2]}
</p>
<p className="text-gray-400 text-sm mb-6">Pour une intervention imm\u00e9diate, appelez directement :</p>
<a
href="tel:+33604408157"
className="inline-flex items-center justify-center gap-3 bg-red-600 hover:bg-red-700 text-white font-bold text-lg px-8 py-4 rounded-xl transition-colors w-full"
>
<svg className="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M3 5a2 2 0 012-2h3.28a1 1 0 01.948.684l1.498 4.493a1 1 0 01-.502 1.21l-2.257 1.13a11.042 11.042 0 005.516 5.516l1.13-2.257a1 1 0 011.21-.502l4.493 1.498a1 1 0 01.684.949V19a2 2 0 01-2 2h-1C9.716 21 3 14.284 3 6V5z" />
</svg>
APPELER MAINTENANT
</a>
<p className="text-gray-400 text-xs mt-3">Disponible 7j/7 &middot; Devis gratuit</p>
</div>
);
}
// Non urgent
return (
<div className="bg-white rounded-2xl p-6 sm:p-8">
<div className="text-center mb-6">
<div className="w-16 h-16 bg-blue-100 rounded-full flex items-center justify-center mx-auto mb-4">
<span className="text-3xl">\u2705</span>
</div>
<h3 className="text-gray-900 font-bold text-xl mb-1">Diagnostic re\u00e7u !</h3>
<p className="text-gray-500 text-sm">
<strong>{answers[0]}</strong> &mdash; {answers[1]} &mdash; {answers[2]}
</p>
</div>
<div className="space-y-4">
<div>
<label className="block text-sm font-medium text-gray-700 mb-1.5">Votre t\u00e9l\u00e9phone</label>
<input type="tel" placeholder="06 12 34 56 78" className="w-full px-4 py-3 bg-gray-50 border border-gray-200 rounded-xl text-gray-800 text-sm placeholder:text-gray-400 focus:border-blue-500 focus:ring-1 focus:ring-blue-500 outline-none" />
</div>
<div>
<label className="block text-sm font-medium text-gray-700 mb-1.5">Pr\u00e9cisions (facultatif)</label>
<textarea rows={2} placeholder="D\u00e9crivez votre probl\u00e8me en quelques mots..." className="w-full px-4 py-3 bg-gray-50 border border-gray-200 rounded-xl text-gray-800 text-sm placeholder:text-gray-400 focus:border-blue-500 focus:ring-1 focus:ring-blue-500 outline-none resize-none" />
</div>
<Button size="lg" className="w-full bg-[#3b82f6] hover:bg-[#2563eb] border-[#3b82f6]">
Envoyer &mdash; On vous rappelle sous 24h
</Button>
</div>
<button onClick={() => { setStep(0); setAnswers([]); }} className="block mx-auto mt-4 text-gray-400 hover:text-gray-600 text-sm underline cursor-pointer">
Recommencer
</button>
</div>
);
}
const q = questions[step];
return (
<div className="bg-white rounded-2xl p-6 sm:p-8">
{/* Progress */}
<div className="flex items-center gap-2 mb-6">
{questions.map((_, i) => (
<div key={i} className={`h-1.5 flex-1 rounded-full transition-colors ${i <= step ? "bg-[#3b82f6]" : "bg-gray-200"}`} />
))}
</div>
<h3 className="text-gray-900 font-bold text-lg mb-5">{q.question}</h3>
<div className="grid grid-cols-1 sm:grid-cols-2 gap-3">
{q.options.map((opt) => (
<button
key={opt.label}
onClick={() => {
setAnswers([...answers, opt.label]);
setStep(step + 1);
}}
className="p-4 rounded-xl border-2 border-gray-200 bg-gray-50 hover:border-[#3b82f6] hover:shadow-md text-left transition-all cursor-pointer"
>
<span className="text-2xl block mb-1">{opt.icon}</span>
<p className="text-gray-900 font-semibold text-sm">{opt.label}</p>
</button>
))}
</div>
{step > 0 && (
<button
onClick={() => { setStep(step - 1); setAnswers(answers.slice(0, -1)); }}
className="mt-4 text-gray-400 hover:text-gray-600 text-sm underline cursor-pointer"
>
&larr; Retour
</button>
)}
</div>
);
}

View File

@@ -1,169 +1,210 @@
import type { Metadata } from "next";
import Link from "next/link";
import Button from "@/components/ui/Button";
import PlombierClient from "./PlombierClient";
export const metadata: Metadata = {
title: "D\u00e9mo Site Plombier / \u00c9lectricien - Pack Urgence & Service",
title: "D\u00e9mo Site Plombier / \u00c9lectricien - L'Intervention \u00c9clair | HookLab",
description:
"D\u00e9couvrez le mod\u00e8le de site HookLab pour plombiers et \u00e9lectriciens. Chargement \u00e9clair, tarifs clairs, formulaire de diagnostic rapide.",
"Mod\u00e8le de site HookLab pour plombiers, \u00e9lectriciens et serruriers. Bouton d\u2019appel sticky, diagnostic en ligne, zone d\u2019intervention, tarifs clairs.",
};
const tarifs = [
{ service: "D\u00e9pannage fuite", prix: "\u00c0 partir de 89\u20ac", urgence: true },
{ service: "Remplacement chauffe-eau", prix: "\u00c0 partir de 350\u20ac", urgence: false },
{ service: "D\u00e9bouchage canalisation", prix: "\u00c0 partir de 120\u20ac", urgence: true },
{ service: "Installation sanitaire", prix: "Sur devis", urgence: false },
{ service: "Remplacement chauffe-eau", prix: "\u00c0 partir de 350\u20ac", urgence: false },
{ service: "Installation sanitaire compl\u00e8te", prix: "Sur devis", urgence: false },
{ service: "Recherche de fuite", prix: "\u00c0 partir de 150\u20ac", urgence: true },
{ service: "R\u00e9novation salle de bain", prix: "Sur devis", urgence: false },
];
const avis = [
{ name: "Laurent P.", ville: "Douai", text: "Fuite \u00e0 22h un samedi. Intervention en 45 min. Prix correct, travail pro. Merci !", note: 5 },
{ name: "Marie C.", ville: "Orchies", text: "Chauffe-eau en panne en plein hiver. Remplac\u00e9 le lendemain matin. Service impeccable.", note: 5 },
{ name: "Jean-Marc B.", ville: "Valenciennes", text: "Canalisation bouch\u00e9e, devis clair au t\u00e9l\u00e9phone, pas de surprise \u00e0 la facture. Rare !", note: 5 },
];
export default function PlombierDemo() {
return (
<main className="min-h-screen bg-bg">
{/* Nav urgence */}
<nav className="sticky top-0 z-50 bg-navy border-b border-white/10">
<main className="min-h-screen bg-[#0a1628]">
{/* Nav avec avis + t\u00e9l */}
<nav className="sticky top-0 z-50 bg-[#0a1628] border-b border-white/10">
<div className="max-w-6xl mx-auto px-4 sm:px-6 lg:px-8 flex items-center justify-between h-16">
<div className="flex items-center gap-3">
<Link href="/" className="text-white/60 hover:text-white text-sm transition-colors">
&larr; Retour HookLab
<Link href="/" className="text-white/50 hover:text-white text-sm transition-colors">
&larr; HookLab
</Link>
<span className="text-white/30">|</span>
<span className="text-white/20">|</span>
<span className="text-white font-bold text-sm">
D\u00e9mo : <span className="text-orange">Pack Urgence</span>
[Votre Entreprise] &mdash; <span className="text-[#3b82f6]">Plombier</span>
</span>
</div>
<a
href="tel:+33600000000"
className="bg-red-600 hover:bg-red-700 text-white font-bold text-sm px-5 py-2.5 rounded-lg transition-colors animate-pulse flex items-center gap-2"
>
<svg className="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M3 5a2 2 0 012-2h3.28a1 1 0 01.948.684l1.498 4.493a1 1 0 01-.502 1.21l-2.257 1.13a11.042 11.042 0 005.516 5.516l1.13-2.257a1 1 0 011.21-.502l4.493 1.498a1 1 0 01.684.949V19a2 2 0 01-2 2h-1C9.716 21 3 14.284 3 6V5z" />
</svg>
URGENCE 7j/7
</a>
<div className="flex items-center gap-3">
{/* Avis Google */}
<div className="hidden sm:flex items-center gap-1.5 bg-yellow-500/10 border border-yellow-500/20 rounded-full px-3 py-1">
<div className="flex gap-0.5">
{[...Array(5)].map((_, i) => (
<svg key={i} className="w-3 h-3 text-yellow-400" fill="currentColor" viewBox="0 0 24 24">
<path d="M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z" />
</svg>
))}
</div>
<span className="text-yellow-300 text-xs font-semibold">4.9/5</span>
</div>
<a
href="tel:+33604408157"
className="bg-[#3b82f6] hover:bg-[#2563eb] text-white font-bold text-sm px-4 py-2 rounded-lg transition-colors flex items-center gap-2"
>
<svg className="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M3 5a2 2 0 012-2h3.28a1 1 0 01.948.684l1.498 4.493a1 1 0 01-.502 1.21l-2.257 1.13a11.042 11.042 0 005.516 5.516l1.13-2.257a1 1 0 011.21-.502l4.493 1.498a1 1 0 01.684.949V19a2 2 0 01-2 2h-1C9.716 21 3 14.284 3 6V5z" />
</svg>
06 04 40 81 57
</a>
</div>
</div>
</nav>
{/* Hero rapide */}
<section className="py-16 md:py-24 bg-navy text-center">
{/* Hero ultra-direct */}
<section className="py-16 md:py-24 bg-[#0a1628] text-center">
<div className="max-w-4xl mx-auto px-4">
<div className="inline-flex items-center gap-2 bg-red-600/20 border border-red-500/30 rounded-full px-4 py-2 mb-6">
<span className="w-2 h-2 bg-red-500 rounded-full animate-pulse" />
<span className="text-red-400 text-xs font-semibold">Disponible 7j/7 &mdash; Intervention rapide</span>
</div>
<h1 className="text-3xl sm:text-4xl md:text-5xl font-extrabold text-white leading-tight mb-6">
[Votre Entreprise] &mdash; Plombier <span className="text-orange">dans le Nord</span>
<h1 className="text-3xl sm:text-4xl md:text-5xl font-extrabold text-white leading-tight mb-4">
Convaincre en{" "}
<span className="text-[#facc15]">3 secondes chrono.</span>
</h1>
<p className="text-white/60 text-lg max-w-2xl mx-auto mb-8">
Fuite, panne, urgence&nbsp;? Intervention rapide sur Douai, Orchies
et Valenciennes. Tarifs transparents, devis gratuit.
<p className="text-white/50 text-lg max-w-2xl mx-auto mb-4">
Quand un client a une fuite d&rsquo;eau ou une panne de courant, il ne veut pas lire
votre histoire. Il veut un num\u00e9ro, un prix, et une arriv\u00e9e rapide.
</p>
<p className="text-white/30 text-sm mb-8">
D\u00e9pannage Douai &middot; Orchies &middot; Valenciennes &middot; Denain &middot; Saint-Amand &middot; Arleux
</p>
<a
href="tel:+33600000000"
className="inline-flex items-center gap-3 bg-red-600 hover:bg-red-700 text-white font-bold text-lg px-8 py-4 rounded-xl transition-colors"
href="tel:+33604408157"
className="inline-flex items-center gap-3 bg-[#3b82f6] hover:bg-[#2563eb] text-white font-bold text-xl px-10 py-5 rounded-2xl transition-colors shadow-lg shadow-blue-500/20"
>
<svg className="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<svg className="w-7 h-7" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M3 5a2 2 0 012-2h3.28a1 1 0 01.948.684l1.498 4.493a1 1 0 01-.502 1.21l-2.257 1.13a11.042 11.042 0 005.516 5.516l1.13-2.257a1 1 0 011.21-.502l4.493 1.498a1 1 0 01.684.949V19a2 2 0 01-2 2h-1C9.716 21 3 14.284 3 6V5z" />
</svg>
Appeler Maintenant
</a>
<p className="text-white/40 text-sm mt-3">Pas de surprise : devis gratuit avant intervention</p>
</div>
</section>
{/* Tarifs clairs */}
<section className="py-16 md:py-24 bg-bg-white">
<section className="py-16 md:py-24 bg-white">
<div className="max-w-4xl mx-auto px-4 sm:px-6 lg:px-8">
<div className="text-center mb-12">
<h2 className="text-2xl md:text-3xl font-bold text-navy mb-3">
Tarifs <span className="text-orange">transparents</span>
<h2 className="text-2xl md:text-3xl font-bold text-gray-900 mb-3">
Tarifs <span className="text-[#3b82f6]">transparents</span>
</h2>
<p className="text-text-light">Pas de surprise. Vous savez ce que vous payez.</p>
<p className="text-gray-500">Pas de surprise. Vous savez ce que vous payez avant qu&rsquo;on se d\u00e9place.</p>
</div>
<div className="space-y-3">
{tarifs.map((t, i) => (
<div key={i} className="flex items-center justify-between bg-bg border border-border rounded-xl p-5">
<div key={i} className="flex items-center justify-between bg-gray-50 border border-gray-200 rounded-xl p-5 hover:shadow-sm transition-shadow">
<div className="flex items-center gap-3">
{t.urgence && (
<span className="w-2 h-2 bg-red-500 rounded-full shrink-0" />
)}
<span className="text-navy font-semibold text-sm">{t.service}</span>
{t.urgence && (
<span className="text-xs bg-red-100 text-red-600 font-semibold px-2 py-0.5 rounded-full">Urgence</span>
)}
{t.urgence && <span className="w-2 h-2 bg-red-500 rounded-full shrink-0" />}
<span className="text-gray-900 font-semibold text-sm">{t.service}</span>
{t.urgence && <span className="text-xs bg-red-100 text-red-600 font-semibold px-2 py-0.5 rounded-full">Urgence</span>}
</div>
<span className="text-orange font-bold text-sm">{t.prix}</span>
<span className="text-[#3b82f6] font-bold text-sm">{t.prix}</span>
</div>
))}
</div>
</div>
</section>
{/* Diagnostic rapide */}
<section className="py-16 md:py-24 bg-bg">
{/* Diagnostic en ligne */}
<section className="py-16 md:py-24 bg-gray-50">
<div className="max-w-2xl mx-auto px-4 sm:px-6 lg:px-8">
<div className="text-center mb-10">
<h2 className="text-2xl md:text-3xl font-bold text-navy mb-3">
Diagnostic <span className="text-orange">rapide</span>
<h2 className="text-2xl md:text-3xl font-bold text-gray-900 mb-3">
Diagnostic <span className="text-[#3b82f6]">en ligne</span>
</h2>
<p className="text-text-light">D\u00e9crivez votre probl\u00e8me en 30 secondes. On vous rappelle avec une solution.</p>
<p className="text-gray-500">3 questions simples. On qualifie la panne avant de d\u00e9crocher.</p>
</div>
<PlombierClient type="diagnostic" />
</div>
</section>
<div className="bg-bg-white border border-border rounded-2xl p-6 sm:p-8">
<div className="space-y-4">
<div>
<label className="block text-sm font-medium text-text mb-1.5">Type de probl\u00e8me</label>
<select className="w-full px-4 py-3 bg-bg border border-border rounded-xl text-text text-sm focus:border-orange focus:ring-1 focus:ring-orange outline-none">
<option>Fuite d&apos;eau</option>
<option>Canalisation bouch\u00e9e</option>
<option>Panne chauffe-eau</option>
<option>Probl\u00e8me radiateur</option>
<option>Autre</option>
</select>
</div>
<div>
<label className="block text-sm font-medium text-text mb-1.5">Niveau d&apos;urgence</label>
<div className="grid grid-cols-3 gap-3">
<div className="border-2 border-red-300 bg-red-50 rounded-xl p-3 text-center cursor-pointer">
<p className="text-red-600 font-bold text-sm">Urgent</p>
<p className="text-text-muted text-xs">Fuite active</p>
</div>
<div className="border border-border rounded-xl p-3 text-center cursor-pointer hover:border-orange transition-colors">
<p className="text-navy font-bold text-sm">Mod\u00e9r\u00e9</p>
<p className="text-text-muted text-xs">Sous 48h</p>
</div>
<div className="border border-border rounded-xl p-3 text-center cursor-pointer hover:border-orange transition-colors">
<p className="text-navy font-bold text-sm">Planifi\u00e9</p>
<p className="text-text-muted text-xs">Travaux</p>
</div>
{/* Avis */}
<section className="py-16 md:py-24 bg-white">
<div className="max-w-4xl mx-auto px-4 text-center">
<h2 className="text-2xl md:text-3xl font-bold text-gray-900 mb-10">
Avis <span className="text-[#facc15]">Google</span> v\u00e9rifi\u00e9s
</h2>
<div className="grid grid-cols-1 md:grid-cols-3 gap-6">
{avis.map((a, i) => (
<div key={i} className="bg-gray-50 border border-gray-200 rounded-xl p-6 text-left">
<div className="flex gap-0.5 mb-3">
{[...Array(a.note)].map((_, j) => (
<svg key={j} className="w-4 h-4 text-yellow-400" fill="currentColor" viewBox="0 0 24 24">
<path d="M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z" />
</svg>
))}
</div>
<p className="text-gray-600 text-sm leading-relaxed mb-3">&ldquo;{a.text}&rdquo;</p>
<p className="text-gray-900 font-semibold text-sm">{a.name} &mdash; <span className="text-gray-400 font-normal">{a.ville}</span></p>
</div>
<div>
<label className="block text-sm font-medium text-text mb-1.5">Votre t\u00e9l\u00e9phone</label>
<input
type="tel"
placeholder="06 12 34 56 78"
className="w-full px-4 py-3 bg-bg border border-border rounded-xl text-text text-sm placeholder:text-text-muted focus:border-orange focus:ring-1 focus:ring-orange outline-none"
/>
</div>
<Button size="lg" className="w-full">
Envoyer le Diagnostic
</Button>
</div>
))}
</div>
</div>
</section>
{/* CTA */}
<section className="py-16 bg-navy text-center">
{/* Zone d'intervention avec carte */}
<section className="py-16 md:py-24 bg-gray-50">
<div className="max-w-4xl mx-auto px-4 sm:px-6 lg:px-8">
<div className="text-center mb-10">
<h2 className="text-2xl md:text-3xl font-bold text-gray-900 mb-3">
Zone <span className="text-[#3b82f6]">d&rsquo;intervention</span>
</h2>
<p className="text-gray-500">Douai + 25km. D\u00e9pannage rapide dans tout le secteur.</p>
</div>
<div className="bg-white border border-gray-200 rounded-2xl overflow-hidden">
<div className="relative h-64 sm:h-80">
<iframe
src="https://www.openstreetmap.org/export/embed.html?bbox=2.6%2C50.2%2C3.8%2C50.55&layer=mapnik&marker=50.4267%2C3.2372"
className="absolute inset-0 w-full h-full border-0"
title="Zone d'intervention plombier"
loading="lazy"
/>
</div>
<div className="p-4 border-t border-gray-100">
<div className="flex flex-wrap gap-2 justify-center">
{["Douai", "Orchies", "Valenciennes", "Denain", "Saint-Amand", "Arleux", "Flines-lez-Raches"].map((v) => (
<span key={v} className="bg-blue-50 text-[#3b82f6] text-xs font-semibold px-3 py-1 rounded-full">{v}</span>
))}
</div>
</div>
</div>
<p className="text-gray-400 text-xs text-center mt-4">
Vous \u00eates hors zone ? Contactez-nous, on trouvera une solution.
</p>
</div>
</section>
{/* Sticky Call Mobile */}
<PlombierClient type="sticky" />
{/* CTA HookLab */}
<section className="py-16 bg-[#3b82f6] text-center">
<div className="max-w-2xl mx-auto px-4">
<p className="text-orange text-xs font-semibold uppercase tracking-wider mb-3">Ceci est une d\u00e9mo HookLab</p>
<p className="text-white/80 text-xs font-semibold uppercase tracking-wider mb-3">Ceci est une d\u00e9mo HookLab</p>
<h2 className="text-2xl md:text-3xl font-bold text-white mb-4">
Ce site peut &ecirc;tre le v&ocirc;tre demain.
Ce site peut \u00eatre le v\u00f4tre demain.
</h2>
<p className="text-white/60 mb-6">
Un site qui rassure, qui qualifie les urgences, et qui vous fait gagner du temps. C&rsquo;est ce que je construis pour les plombiers et \u00e9lectriciens du Nord.
<p className="text-white/80 mb-6">
Un site qui rassure, qui qualifie les urgences, et qui vous fait gagner du temps.
C&rsquo;est ce que je construis pour les plombiers et \u00e9lectriciens du Nord.
</p>
<Link href="/#contact">
<Button size="lg" className="pulse-glow">
<Button size="lg" className="bg-[#0a1628] hover:bg-[#0a1628]/90 border-[#0a1628]">
Demander Mon Audit Gratuit
</Button>
</Link>

View File

@@ -0,0 +1,19 @@
import type { Metadata } from "next";
import LocalSeoPage from "@/components/marketing/LocalSeoPage";
export const metadata: Metadata = {
title: "Création Site Internet Artisan Arleux (59) | HookLab",
description:
"Création de sites internet pour artisans à Arleux et environs. Visibilité Google, site ultra-rapide, système de confiance. Audit gratuit.",
};
export default function Page() {
return (
<LocalSeoPage
ville="Arleux"
villeSlug="arleux"
codePostal="59151"
voisines={["Douai", "Orchies", "Flines-lez-Raches"]}
/>
);
}

View File

@@ -0,0 +1,19 @@
import type { Metadata } from "next";
import LocalSeoPage from "@/components/marketing/LocalSeoPage";
export const metadata: Metadata = {
title: "Création Site Internet Artisan Denain (59) | HookLab",
description:
"Sites web professionnels pour artisans du bâtiment à Denain. Maçon, couvreur, plombier, paysagiste. SEO local + audit offert.",
};
export default function Page() {
return (
<LocalSeoPage
ville="Denain"
villeSlug="denain"
codePostal="59220"
voisines={["Valenciennes", "Douai", "Saint-Amand-les-Eaux"]}
/>
);
}

View File

@@ -0,0 +1,19 @@
import type { Metadata } from "next";
import LocalSeoPage from "@/components/marketing/LocalSeoPage";
export const metadata: Metadata = {
title: "Création Site Internet Artisan Douai (59) | HookLab",
description:
"Spécialiste création de sites web pour artisans du bâtiment à Douai et environs. Couvreur, maçon, paysagiste, plombier. Audit gratuit.",
};
export default function Page() {
return (
<LocalSeoPage
ville="Douai"
villeSlug="douai"
codePostal="59500"
voisines={["Orchies", "Arleux", "Flines-lez-Raches"]}
/>
);
}

View File

@@ -0,0 +1,19 @@
import type { Metadata } from "next";
import LocalSeoPage from "@/components/marketing/LocalSeoPage";
export const metadata: Metadata = {
title: "Création Site Internet Artisan Orchies (59) | HookLab",
description:
"Création de sites web professionnels pour artisans à Orchies. Couvreur, maçon, paysagiste. Site rapide + SEO local. Audit offert.",
};
export default function Page() {
return (
<LocalSeoPage
ville="Orchies"
villeSlug="orchies"
codePostal="59310"
voisines={["Douai", "Flines-lez-Raches", "Saint-Amand-les-Eaux"]}
/>
);
}

View File

@@ -0,0 +1,19 @@
import type { Metadata } from "next";
import LocalSeoPage from "@/components/marketing/LocalSeoPage";
export const metadata: Metadata = {
title: "Création Site Internet Artisan Saint-Amand-les-Eaux (59) | HookLab",
description:
"Votre site web professionnel d'artisan à Saint-Amand-les-Eaux. Couvreur, plombier, paysagiste. Conçu pour générer des chantiers. Audit offert.",
};
export default function Page() {
return (
<LocalSeoPage
ville="Saint-Amand-les-Eaux"
villeSlug="saint-amand-les-eaux"
codePostal="59230"
voisines={["Valenciennes", "Orchies", "Denain"]}
/>
);
}

View File

@@ -0,0 +1,19 @@
import type { Metadata } from "next";
import LocalSeoPage from "@/components/marketing/LocalSeoPage";
export const metadata: Metadata = {
title: "Création Site Internet Artisan Valenciennes (59) | HookLab",
description:
"Sites web pour artisans du bâtiment à Valenciennes et Valenciennois. Technologie ultra-rapide, SEO local, résultats concrets. Audit gratuit.",
};
export default function Page() {
return (
<LocalSeoPage
ville="Valenciennes"
villeSlug="valenciennes"
codePostal="59300"
voisines={["Denain", "Saint-Amand-les-Eaux", "Douai"]}
/>
);
}

View File

@@ -1,26 +1,101 @@
import type { MetadataRoute } from "next";
const BASE_URL = process.env.NEXT_PUBLIC_APP_URL || "https://hooklab.eu";
const BASE_URL = "https://www.hooklab.eu";
export default function sitemap(): MetadataRoute.Sitemap {
const now = new Date();
return [
// Page d'accueil - priorit\u00e9 max
{
url: BASE_URL,
lastModified: new Date(),
lastModified: now,
changeFrequency: "weekly",
priority: 1.0,
},
// D\u00e9mos m\u00e9tiers - pages strat\u00e9giques SEO
{
url: `${BASE_URL}/macon`,
lastModified: now,
changeFrequency: "monthly",
priority: 0.9,
},
{
url: `${BASE_URL}/paysagiste`,
lastModified: now,
changeFrequency: "monthly",
priority: 0.9,
},
{
url: `${BASE_URL}/plombier`,
lastModified: now,
changeFrequency: "monthly",
priority: 0.9,
},
// Pages SEO locales - site internet artisan + ville
// Douai
{
url: `${BASE_URL}/site-internet-artisan-douai`,
lastModified: now,
changeFrequency: "monthly",
priority: 0.8,
},
// Orchies
{
url: `${BASE_URL}/site-internet-artisan-orchies`,
lastModified: now,
changeFrequency: "monthly",
priority: 0.8,
},
// Valenciennes
{
url: `${BASE_URL}/site-internet-artisan-valenciennes`,
lastModified: now,
changeFrequency: "monthly",
priority: 0.8,
},
// Saint-Amand-les-Eaux
{
url: `${BASE_URL}/site-internet-artisan-saint-amand-les-eaux`,
lastModified: now,
changeFrequency: "monthly",
priority: 0.8,
},
// Arleux
{
url: `${BASE_URL}/site-internet-artisan-arleux`,
lastModified: now,
changeFrequency: "monthly",
priority: 0.8,
},
// Denain
{
url: `${BASE_URL}/site-internet-artisan-denain`,
lastModified: now,
changeFrequency: "monthly",
priority: 0.8,
},
// L\u00e9gal
{
url: `${BASE_URL}/mentions-legales`,
lastModified: new Date(),
lastModified: now,
changeFrequency: "yearly",
priority: 0.3,
priority: 0.2,
},
{
url: `${BASE_URL}/confidentialite`,
lastModified: new Date(),
lastModified: now,
changeFrequency: "yearly",
priority: 0.3,
priority: 0.2,
},
{
url: `${BASE_URL}/plan-du-site`,
lastModified: now,
changeFrequency: "yearly",
priority: 0.2,
},
];
}

View File

@@ -3,11 +3,11 @@ import Link from "next/link";
const demos = [
{
title: "Le Pack \u00ab\u00a0Gros \u0152uvre\u00a0\u00bb",
subtitle: "Ma\u00e7on / Couvreur",
title: "L\u2019Expertise Solide",
subtitle: "Pour ceux dont le travail doit durer 100 ans.",
pourQui: "Ma\u00e7ons, Couvreurs, Charpentiers.",
pointFort: "La galerie \u00ab\u00a0Avant / Apr\u00e8s\u00a0\u00bb qui prouve votre technique et justifie vos devis.",
fonctionnalite: "Bouton \u00ab\u00a0Urgence Fuite\u00a0\u00bb qui d\u00e9clenche l\u2019appel imm\u00e9diat.",
pointFort: "Slider \u00ab\u00a0Avant / Apr\u00e8s\u00a0\u00bb interactif + badges garanties (D\u00e9cennale, Qualibat, RGE) immanquables.",
fonctionnalite: "Formulaire intelligent : si Urgence Fuite \u2192 bouton rouge \u00ab\u00a0APPELER LE PATRON\u00a0\u00bb.",
cta: "Voir la D\u00e9mo Ma\u00e7onnerie",
href: "/macon",
icon: (
@@ -17,11 +17,11 @@ const demos = [
),
},
{
title: "Le Pack \u00ab\u00a0Esth\u00e9tique\u00a0\u00bb",
subtitle: "Paysagiste / Peintre",
title: "L\u2019Artisan Cr\u00e9ateur",
subtitle: "Pour ceux qui vendent du beau et du confort.",
pourQui: "Paysagistes, Peintres, D\u00e9corateurs.",
pointFort: "Un design \u00e9pur\u00e9 qui laisse toute la place \u00e0 la beaut\u00e9 de vos r\u00e9alisations.",
fonctionnalite: "Filtrage \u00ab\u00a0Cr\u00e9ation vs Entretien\u00a0\u00bb pour ne recevoir que les projets \u00e0 forte valeur.",
pointFort: "Galerie filtrable par type + saisonnalit\u00e9 intelligente (le site change selon la saison).",
fonctionnalite: "Bouton WhatsApp flottant \u00ab\u00a0Je veux le m\u00eame jardin\u00a0\u00bb + immersion locale par ville.",
cta: "Voir la D\u00e9mo Paysagiste",
href: "/paysagiste",
icon: (
@@ -31,11 +31,11 @@ const demos = [
),
},
{
title: "Le Pack \u00ab\u00a0Urgence & Service\u00a0\u00bb",
subtitle: "Plombier / \u00c9lec",
title: "L\u2019Intervention \u00c9clair",
subtitle: "Pour ceux qui sauvent la mise (et veulent \u00eatre pay\u00e9s vite).",
pourQui: "Plombiers, \u00c9lectriciens, Serruriers.",
pointFort: "Vitesse de chargement \u00e9clair et rassurance imm\u00e9diate (Avis + Tarifs clairs).",
fonctionnalite: "Formulaire de diagnostic rapide pour qualifier la panne avant de vous d\u00e9placer.",
pointFort: "Avis Google en haut + tarifs transparents + bouton d\u2019appel sticky sur mobile.",
fonctionnalite: "Diagnostic en 3 clics : qualifie la panne + d\u00e9tecte si hors zone.",
cta: "Voir la D\u00e9mo Plombier",
href: "/plombier",
icon: (

View File

@@ -0,0 +1,142 @@
import Link from "next/link";
import Button from "@/components/ui/Button";
import Navbar from "@/components/marketing/Navbar";
import Footer from "@/components/marketing/Footer";
interface LocalSeoPageProps {
ville: string;
villeSlug: string;
codePostal: string;
voisines: string[];
}
export default function LocalSeoPage({ ville, codePostal, voisines }: LocalSeoPageProps) {
return (
<main className="min-h-screen">
<Navbar />
{/* Hero local */}
<section className="py-20 md:py-28 bg-navy text-center">
<div className="max-w-4xl mx-auto px-4">
<span className="inline-block px-3 py-1.5 bg-orange/20 border border-orange/30 rounded-full text-orange text-xs font-semibold mb-6">
{ville} ({codePostal}) et environs
</span>
<h1 className="text-3xl sm:text-4xl md:text-5xl font-extrabold text-white leading-tight mb-6">
Cr&eacute;ation de site internet pour{" "}
<span className="text-orange">artisans &agrave; {ville}</span>
</h1>
<p className="text-white/60 text-lg max-w-2xl mx-auto mb-8">
Vous &ecirc;tes artisan &agrave; {ville} ou dans le secteur de {voisines[0]} / {voisines[1]} ?
Je cr&eacute;e votre site web professionnel et votre pr&eacute;sence Google pour g&eacute;n&eacute;rer
des chantiers qualifi&eacute;s. Bas&eacute; &agrave; Flines-lez-Raches, je suis votre voisin.
</p>
<a href="/#contact">
<Button size="lg" className="pulse-glow">
D&Eacute;MARRER MON AUDIT GRATUIT
</Button>
</a>
<p className="mt-4 text-white/40 text-sm">
R&eacute;ponse sous 24h &middot; 100% gratuit &middot; Sans engagement
</p>
</div>
</section>
{/* M\u00e9tiers couverts */}
<section className="py-16 md:py-24 bg-bg">
<div className="max-w-4xl mx-auto px-4 sm:px-6 lg:px-8">
<h2 className="text-2xl md:text-3xl font-bold text-navy text-center mb-10">
Sites web pour <span className="text-orange">tous les m&eacute;tiers du b&acirc;timent</span> &agrave; {ville}
</h2>
<div className="grid grid-cols-2 md:grid-cols-3 gap-4">
{[
"Couvreur", "Ma\u00e7on", "Paysagiste",
"Plombier", "\u00c9lectricien", "Menuisier",
"Charpentier", "Peintre", "Serrurier",
].map((metier) => (
<div key={metier} className="bg-bg-white border border-border rounded-xl p-4 text-center hover:shadow-md transition-shadow">
<p className="text-navy font-semibold text-sm">Site internet {metier}</p>
<p className="text-text-muted text-xs mt-1">{ville} et environs</p>
</div>
))}
</div>
</div>
</section>
{/* Pourquoi HookLab */}
<section className="py-16 md:py-24 bg-bg-white">
<div className="max-w-3xl mx-auto px-4 text-center">
<h2 className="text-2xl md:text-3xl font-bold text-navy mb-6">
Pourquoi choisir <span className="text-orange">HookLab</span> &agrave; {ville} ?
</h2>
<div className="space-y-4 text-left">
{[
{
title: "Proximit\u00e9 locale",
desc: `Bas\u00e9 \u00e0 Flines-lez-Raches, je connais ${ville} et ses artisans. On peut se voir en vrai.`,
},
{
title: "Technologie des g\u00e9ants",
desc: "Sites ultra-rapides avec la m\u00eame technologie que Netflix. Google adore la vitesse.",
},
{
title: "R\u00e9sultats concrets",
desc: "Pas un site pour faire joli. Un syst\u00e8me qui fait sonner votre t\u00e9l\u00e9phone avec des vrais clients.",
},
].map((item, i) => (
<div key={i} className="flex items-start gap-4 bg-bg border border-border rounded-xl p-5">
<div className="w-8 h-8 bg-orange/10 rounded-full flex items-center justify-center shrink-0 mt-0.5">
<svg className="w-4 h-4 text-orange" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2.5} d="M5 13l4 4L19 7" />
</svg>
</div>
<div>
<p className="text-navy font-bold text-base mb-1">{item.title}</p>
<p className="text-text-light text-sm leading-relaxed">{item.desc}</p>
</div>
</div>
))}
</div>
</div>
</section>
{/* D\u00e9mos */}
<section className="py-16 md:py-24 bg-bg">
<div className="max-w-4xl mx-auto px-4 text-center">
<h2 className="text-2xl md:text-3xl font-bold text-navy mb-6">
Testez nos <span className="text-orange">mod&egrave;les</span>
</h2>
<div className="flex flex-wrap gap-4 justify-center">
<Link href="/macon" className="bg-navy text-white font-bold text-sm px-6 py-3 rounded-xl hover:bg-navy/90 transition-colors">
D&eacute;mo Ma&ccedil;on / Couvreur
</Link>
<Link href="/paysagiste" className="bg-green-600 text-white font-bold text-sm px-6 py-3 rounded-xl hover:bg-green-700 transition-colors">
D&eacute;mo Paysagiste
</Link>
<Link href="/plombier" className="bg-[#3b82f6] text-white font-bold text-sm px-6 py-3 rounded-xl hover:bg-[#2563eb] transition-colors">
D&eacute;mo Plombier
</Link>
</div>
</div>
</section>
{/* Zone */}
<section className="py-16 bg-navy text-center">
<div className="max-w-2xl mx-auto px-4">
<h2 className="text-2xl font-bold text-white mb-4">
Aussi disponible &agrave; {voisines.join(", ")}
</h2>
<p className="text-white/60 mb-6">
Je travaille avec des artisans dans tout le Douaisis, l&rsquo;Orch&eacute;sien et le Valenciennois.
</p>
<a href="/#contact">
<Button size="lg" className="pulse-glow">
R&eacute;server Mon Audit Gratuit
</Button>
</a>
</div>
</section>
<Footer />
</main>
);
}

View File

@@ -36,13 +36,13 @@ export default function Navbar() {
{/* CTA desktop - Phone */}
<div className="hidden md:block">
<a
href="tel:+33600000000"
href="tel:+33604408157"
className="inline-flex items-center gap-2 bg-orange text-white font-bold text-sm px-5 py-2.5 rounded-xl hover:bg-orange/90 transition-colors"
>
<svg className="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M3 5a2 2 0 012-2h3.28a1 1 0 01.948.684l1.498 4.493a1 1 0 01-.502 1.21l-2.257 1.13a11.042 11.042 0 005.516 5.516l1.13-2.257a1 1 0 011.21-.502l4.493 1.498a1 1 0 01.684.949V19a2 2 0 01-2 2h-1C9.716 21 3 14.284 3 6V5z" />
</svg>
06 XX XX XX XX
06 04 40 81 57
</a>
</div>
@@ -78,14 +78,14 @@ export default function Navbar() {
Qui suis-je
</a>
<a
href="tel:+33600000000"
href="tel:+33604408157"
onClick={() => setOpen(false)}
className="flex items-center justify-center gap-2 bg-orange text-white font-bold text-sm px-5 py-3 rounded-xl mt-2"
>
<svg className="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M3 5a2 2 0 012-2h3.28a1 1 0 01.948.684l1.498 4.493a1 1 0 01-.502 1.21l-2.257 1.13a11.042 11.042 0 005.516 5.516l1.13-2.257a1 1 0 011.21-.502l4.493 1.498a1 1 0 01.684.949V19a2 2 0 01-2 2h-1C9.716 21 3 14.284 3 6V5z" />
</svg>
06 XX XX XX XX
06 04 40 81 57
</a>
</div>
)}

View File

@@ -0,0 +1,91 @@
"use client";
import { useState, useRef, useCallback } from "react";
interface MagicRevealProps {
avantLabel: string;
apresLabel: string;
avantColor?: string;
apresColor?: string;
height?: string;
}
export default function MagicReveal({
avantLabel,
apresLabel,
avantColor = "bg-red-50",
apresColor = "bg-green-50",
height = "h-64",
}: MagicRevealProps) {
const [position, setPosition] = useState(50);
const containerRef = useRef<HTMLDivElement>(null);
const dragging = useRef(false);
const updatePosition = useCallback((clientX: number) => {
if (!containerRef.current) return;
const rect = containerRef.current.getBoundingClientRect();
const x = clientX - rect.left;
const percent = Math.max(0, Math.min(100, (x / rect.width) * 100));
setPosition(percent);
}, []);
const handlePointerDown = useCallback((e: React.PointerEvent) => {
dragging.current = true;
(e.target as HTMLElement).setPointerCapture(e.pointerId);
updatePosition(e.clientX);
}, [updatePosition]);
const handlePointerMove = useCallback((e: React.PointerEvent) => {
if (!dragging.current) return;
updatePosition(e.clientX);
}, [updatePosition]);
const handlePointerUp = useCallback(() => {
dragging.current = false;
}, []);
return (
<div
ref={containerRef}
className={`relative ${height} rounded-xl overflow-hidden cursor-col-resize select-none border border-border`}
onPointerDown={handlePointerDown}
onPointerMove={handlePointerMove}
onPointerUp={handlePointerUp}
>
{/* Apr\u00e8s (fond complet) */}
<div className={`absolute inset-0 ${apresColor} flex items-center justify-center`}>
<div className="text-center">
<p className="text-green-600 font-bold text-sm uppercase tracking-wider mb-1">Apr\u00e8s</p>
<p className="text-green-800 text-sm font-medium px-4">{apresLabel}</p>
</div>
</div>
{/* Avant (clip\u00e9 \u00e0 gauche) */}
<div
className={`absolute inset-0 ${avantColor} flex items-center justify-center`}
style={{ clipPath: `inset(0 ${100 - position}% 0 0)` }}
>
<div className="text-center">
<p className="text-red-600 font-bold text-sm uppercase tracking-wider mb-1">Avant</p>
<p className="text-red-800 text-sm font-medium px-4">{avantLabel}</p>
</div>
</div>
{/* Barre de s\u00e9paration */}
<div
className="absolute top-0 bottom-0 w-1 bg-white shadow-lg z-10"
style={{ left: `${position}%`, transform: "translateX(-50%)" }}
>
<div className="absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 w-10 h-10 bg-white rounded-full shadow-lg flex items-center justify-center border-2 border-orange">
<svg className="w-5 h-5 text-orange" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M8 9l4-4 4 4m0 6l-4 4-4-4" />
</svg>
</div>
</div>
{/* Labels gauche/droite */}
<div className="absolute top-2 left-3 bg-red-600 text-white text-[10px] font-bold px-2 py-0.5 rounded-full z-20">AVANT</div>
<div className="absolute top-2 right-3 bg-green-600 text-white text-[10px] font-bold px-2 py-0.5 rounded-full z-20">APR\u00c8S</div>
</div>
);
}