feat: préparation Payload CMS — couche d'abstraction contenu

Sépare données et affichage pour basculer vers Payload CMS sans réécrire les composants.

Nouveaux fichiers :
- lib/site-config.ts : source unique de vérité pour toutes les données du site (as const)
- lib/content.ts : couche async entre données et composants (static aujourd'hui, Payload demain)
- types/content.ts : types TypeScript partagés (Service, Realisation, Partner, BlogPost, etc.)
- payload/ : schémas CollectionConfig et GlobalConfig commentés prêts à activer

Données enrichies dans siteConfig :
- partners : ajout du champ desc pour chaque partenaire
- realisations : 6 entrées complètes avec categorie et color
- blogPosts : 6 articles avec slug, titre, extrait, cat, date, readTime

Refactorisations (composants → content layer) :
- Navbar, Footer : importent siteConfig directement (client component)
- app/page.tsx : async, Promise.all sur getServices/getTestimonials/getFAQ/getValues/getPartners/getRealisations
- app/services/page.tsx : getServices() + getSiteConfig()
- app/contact/page.tsx : getSiteConfig() pour phone, email, address, zones
- app/realisations/page.tsx : getRealisations() + getSiteConfig()
- app/partenaires/page.tsx : getPartners()
- app/blog/page.tsx : getBlogPosts()
- app/blog/[slug]/page.tsx : getBlogPost() + getBlogPosts() pour generateStaticParams
- LocalSEOPage.tsx : siteConfig pour services list, phone, address
- 5 pages service (construction-maison, renovation, assainissement, creation-acces, demolition) : getSiteConfig() pour phone
- Pages légales et SEO locales : siteConfig importé pour données dynamiques

Corrections URL :
- Toutes les URLs canoniques obc-maconnerie.fr → obc-terrassement.fr (30+ fichiers)
- layout.tsx : BASE_URL depuis siteConfig.url
- robots.ts, sitemap.ts : BASE_URL depuis siteConfig.url
- api/contact/route.ts : email fallback → obc-terrassement.fr

https://claude.ai/code/session_01Uec4iHjcPwB1pU41idWEdF
This commit is contained in:
Claude
2026-02-27 13:05:19 +00:00
parent 3adcec00b7
commit 15c60a274c
40 changed files with 1534 additions and 860 deletions

View File

@@ -31,8 +31,8 @@ export async function POST(request: Request) {
const { Resend } = await import("resend");
const resend = new Resend(process.env.RESEND_API_KEY);
const fromEmail = process.env.RESEND_FROM_EMAIL || "OBC Maçonnerie <contact@obc-maconnerie.fr>";
const adminEmail = process.env.ADMIN_EMAIL || "contact@obc-maconnerie.fr";
const fromEmail = process.env.RESEND_FROM_EMAIL || "OBC Maçonnerie <contact@obc-terrassement.fr>";
const adminEmail = process.env.ADMIN_EMAIL || "contact@obc-terrassement.fr";
await resend.emails.send({
from: fromEmail,

View File

@@ -4,8 +4,12 @@ import Navbar from "@/components/marketing/Navbar";
import Footer from "@/components/marketing/Footer";
import ScrollReveal from "@/components/animations/ScrollReveal";
import ContactForm from "@/components/marketing/ContactForm";
import { getSiteConfig } from "@/lib/content";
export async function generateMetadata(): Promise<Metadata> {
const config = await getSiteConfig();
return {
export const metadata: Metadata = {
title: "Assainissement Maison Nord 59 | OBC Maçonnerie",
description:
"Création et mise aux normes de systèmes d'assainissement dans le Nord (59). OBC Maçonnerie intervient à Orchies, Douai, Valenciennes et alentours. Devis gratuit.",
@@ -17,8 +21,9 @@ export const metadata: Metadata = {
"assainissement Orchies",
"assainissement Douai",
],
alternates: { canonical: "https://obc-maconnerie.fr/assainissement" },
alternates: { canonical: `${config.url}/assainissement` },
};
}
const prestations = [
{ icon: "🔍", title: "Diagnostic", desc: "Analyse de votre installation existante et vérification de sa conformité aux normes en vigueur." },
@@ -29,7 +34,9 @@ const prestations = [
{ icon: "💧", title: "Raccordement réseau", desc: "Connexion au réseau d'assainissement collectif lorsque celui-ci est disponible." },
];
export default function AssainissementPage() {
export default async function AssainissementPage() {
const config = await getSiteConfig();
const { phone, phoneRaw } = config;
return (
<main id="main-content" className="min-h-screen">
<Navbar />
@@ -55,9 +62,7 @@ export default function AssainissementPage() {
<Link href="/contact" className="inline-flex items-center justify-center gap-2 bg-orange hover:bg-orange-hover text-white font-bold px-7 py-3.5 rounded-xl transition-colors pulse-glow">
Demander un devis gratuit
</Link>
<a href="tel:0674453089" className="inline-flex items-center justify-center gap-2 bg-white/10 hover:bg-white/20 text-white font-semibold px-7 py-3.5 rounded-xl transition-colors border border-white/20">
06 74 45 30 89
</a>
<a href={`tel:${phoneRaw}`} className="inline-flex items-center justify-center gap-2 bg-white/10 hover:bg-white/20 text-white font-semibold px-7 py-3.5 rounded-xl transition-colors border border-white/20">{phone}</a>
</div>
</ScrollReveal>
</div>

View File

@@ -4,28 +4,13 @@ import { notFound } from "next/navigation";
import Navbar from "@/components/marketing/Navbar";
import Footer from "@/components/marketing/Footer";
import ScrollReveal from "@/components/animations/ScrollReveal";
import { getBlogPost, getBlogPosts, getSiteConfig } from "@/lib/content";
type Props = { params: Promise<{ slug: string }> };
const articles: Record<
string,
{
titre: string;
description: string;
cat: string;
date: string;
readTime: string;
contenu: string[];
}
> = {
"combien-coute-construction-maison-nord": {
titre: "Combien coûte la construction d'une maison dans le Nord en 2025 ?",
description:
"Budget, matériaux, terrain, main-d'œuvre — tout ce qu'il faut savoir pour estimer le coût de votre construction neuve dans le Nord.",
cat: "Construction",
date: "15 février 2025",
readTime: "6 min",
contenu: [
// Corps des articles — FUTURE: champ rich text Payload CMS
const articleContenu: Record<string, string[]> = {
"combien-coute-construction-maison-nord": [
"La construction d'une maison individuelle dans le Nord représente un investissement significatif. En 2025, le coût moyen se situe entre 1 200 € et 1 800 € par m² hors terrain et hors raccordements, selon les matériaux choisis et la complexité du projet.",
"**Le prix du terrain** est souvent la première variable. Dans le secteur d'Orchies et de Mouchin, comptez entre 50 000 € et 120 000 € pour une parcelle constructible de 400 à 600 m².",
"**Le gros œuvre** (fondations, murs, dalle, toiture) représente environ 40 à 50% du budget total. C'est là qu'intervient OBC Maçonnerie avec son savoir-faire et son réseau de partenaires pour optimiser les coûts sans sacrifier la qualité.",
@@ -33,15 +18,7 @@ const articles: Record<
"Pour un projet de 100 m² habitable à Orchies ou Douai, un budget total entre 180 000 € et 280 000 € (hors terrain) est réaliste selon le niveau de finition souhaité.",
"Le meilleur conseil : contactez Benoît Colin pour une évaluation gratuite de votre projet. Il vous donnera une estimation précise adaptée à votre terrain et vos envies.",
],
},
"etapes-renovation-maison-ancienne": {
titre: "Les étapes clés d'une rénovation de maison ancienne",
description:
"Vous avez acheté une maison ancienne dans le Nord et vous voulez la rénover ? Voici les étapes indispensables pour réussir votre projet.",
cat: "Rénovation",
date: "8 janvier 2025",
readTime: "5 min",
contenu: [
"etapes-renovation-maison-ancienne": [
"Rénover une maison ancienne dans le Nord demande une méthodologie rigoureuse. Voici les grandes étapes pour mener votre projet à bien.",
"**1. Le diagnostic** : Avant tout, il faut évaluer l'état du bâtiment. Charpente, toiture, murs porteurs, fondations, réseaux électriques et plomberie — tout doit être passé en revue. Un maçon expérimenté comme Benoît Colin peut repérer les problèmes invisibles à l'œil nu.",
"**2. La démolition et le curage** : On enlève ce qui est vétuste ou inadapté — cloisons obsolètes, chapes abîmées, enduits défaillants — pour repartir sur de bonnes bases.",
@@ -50,30 +27,14 @@ const articles: Record<
"**5. Les finitions** : Menuiseries, carrelage, peinture, revêtements de sol. La touche finale qui donne tout son caractère à votre maison rénovée.",
"Chaque rénovation est unique. Contactez OBC Maçonnerie pour une évaluation gratuite de votre projet.",
],
},
"assainissement-non-collectif-obligations": {
titre: "Assainissement non collectif : vos obligations légales",
description:
"Contrôle SPANC, mise aux normes, vente immobilière — tout ce que vous devez savoir sur l'assainissement non collectif.",
cat: "Assainissement",
date: "20 décembre 2024",
readTime: "4 min",
contenu: [
"assainissement-non-collectif-obligations": [
"En France, environ 5 millions de logements sont équipés d'un assainissement non collectif (ANC). Si votre maison n'est pas raccordée au réseau public, vous êtes soumis à des obligations précises.",
"**Le contrôle SPANC** : Le Service Public d'Assainissement Non Collectif peut contrôler votre installation. En cas de non-conformité, vous avez en principe 4 ans pour mettre aux normes, ou moins si vous vendez le bien.",
"**La vente immobilière** : Depuis 2011, un diagnostic d'assainissement est obligatoire lors de toute vente. S'il révèle une non-conformité, l'acheteur doit réaliser les travaux dans l'année suivant l'acte de vente.",
"**Les principales normes** : Votre installation doit traiter correctement les eaux usées avant rejet dans le sol. Les normes imposent une fosse toutes eaux (ou une micro-station) et un dispositif d'épandage adapté à la surface disponible.",
"**OBC Maçonnerie vous accompagne** dans la mise aux normes ou la création de votre système d'assainissement non collectif. Nous intervenons sur Orchies, Douai, Valenciennes et toute la zone.",
],
},
"ossature-bois-avantages": {
titre: "Ossature bois : pourquoi choisir ce mode constructif ?",
description:
"Légèreté, performance thermique, rapidité de construction — l'ossature bois a de nombreux avantages. OBC Maçonnerie vous explique.",
cat: "Construction",
date: "5 novembre 2024",
readTime: "5 min",
contenu: [
"ossature-bois-avantages": [
"La construction en ossature bois connaît un vrai succès dans le Nord. Et pour cause : ce mode constructif présente de nombreux avantages techniques et économiques.",
"**Performance thermique** : Le bois est un excellent isolant naturel. Une construction ossature bois bien conçue atteint facilement les exigences RE2020.",
"**Rapidité de chantier** : Les éléments préfabriqués permettent de monter les murs en quelques jours. Le clos-couvert est obtenu très rapidement.",
@@ -81,15 +42,7 @@ const articles: Record<
"**Polyvalence architecturale** : L'ossature bois permet des formes architecturales variées, des larges baies vitrées et une grande liberté de conception.",
"**La combinaison idéale** : OBC Maçonnerie maîtrise la construction ossature bois et la maçonnerie traditionnelle. Benoît vous conseille sur la solution la plus adaptée à votre terrain et vos envies.",
],
},
"travaux-renovation-sans-permis-construction": {
titre: "Quels travaux de rénovation ne nécessitent pas de permis ?",
description:
"Permis de construire, déclaration préalable, simple déclaration — on vous explique les règles selon la nature de vos travaux.",
cat: "Rénovation",
date: "18 octobre 2024",
readTime: "4 min",
contenu: [
"travaux-renovation-sans-permis-construction": [
"Avant de démarrer des travaux de rénovation, il est important de savoir si vous avez besoin d'une autorisation administrative.",
"**Aucune démarche requise** : Les travaux purement intérieurs (peinture, revêtements, redistribution de cloisons non porteuses, remplacement de fenêtres à l'identique) ne nécessitent généralement aucune démarche.",
"**Déclaration préalable** : Pour les extensions jusqu'à 40 m² (en zone urbaine PLU), les changements de façade, les travaux modifiant l'aspect extérieur.",
@@ -97,15 +50,7 @@ const articles: Record<
"**Cas des zones protégées** : Si votre maison est en zone ABF (Architecte des Bâtiments de France), les règles sont plus strictes. Renseignez-vous en mairie.",
"En cas de doute, OBC Maçonnerie vous accompagne dans vos démarches administratives. Benoît connaît bien les règles locales dans le secteur d'Orchies, Douai et Valenciennes.",
],
},
"fondations-maison-quels-types": {
titre: "Les différents types de fondations pour une maison",
description:
"Semelles filantes, radier, pieux — quelles fondations choisir selon votre terrain et votre projet de construction ?",
cat: "Construction",
date: "2 septembre 2024",
readTime: "5 min",
contenu: [
"fondations-maison-quels-types": [
"Les fondations sont la base de toute construction. Mal dimensionnées ou inadaptées au sol, elles peuvent entraîner des désordres graves. Voici les principaux types.",
"**Les semelles filantes** : Le type le plus courant pour les maisons individuelles. Elles répartissent les charges des murs porteurs sur une bande de terrain. Adaptées aux sols stables et homogènes.",
"**Le radier** : Une dalle béton armé qui couvre toute la surface de la maison. Recommandé sur les terrains argileux, instables ou avec présence d'eau. Fréquent dans certains secteurs du Nord.",
@@ -113,28 +58,31 @@ const articles: Record<
"**L'étude de sol** : Avant toute construction, une étude géotechnique (étude de sol) est vivement recommandée — et même obligatoire dans certains cas (zones argileuses). Elle permet de choisir le bon type de fondations.",
"OBC Maçonnerie réalise vos fondations avec rigueur, après analyse du terrain. Benoît vous conseille sur la solution la plus adaptée à votre projet dans le Nord.",
],
},
};
export async function generateStaticParams() {
return Object.keys(articles).map((slug) => ({ slug }));
// FUTURE: utilise getBlogPosts() pour générer les slugs depuis Payload CMS
const posts = await getBlogPosts();
return posts.map((p) => ({ slug: p.slug }));
}
export async function generateMetadata({ params }: Props): Promise<Metadata> {
const { slug } = await params;
const article = articles[slug];
if (!article) return { title: "Article introuvable" };
const [post, config] = await Promise.all([getBlogPost(slug), getSiteConfig()]);
if (!post) return { title: "Article introuvable" };
return {
title: article.titre,
description: article.description,
alternates: { canonical: `https://obc-maconnerie.fr/blog/${slug}` },
title: post.titre,
description: post.extrait,
alternates: { canonical: `${config.url}/blog/${slug}` },
};
}
export default async function BlogArticlePage({ params }: Props) {
const { slug } = await params;
const article = articles[slug];
if (!article) notFound();
const post = await getBlogPost(slug);
if (!post) notFound();
const contenu = articleContenu[slug] ?? [];
return (
<main id="main-content" className="min-h-screen">
@@ -151,13 +99,13 @@ export default async function BlogArticlePage({ params }: Props) {
</Link>
<div className="flex items-center gap-3 mb-4">
<span className="bg-orange/20 text-orange text-xs font-semibold px-2.5 py-1 rounded-full">
{article.cat}
{post.cat}
</span>
<span className="text-white/40 text-xs">{article.date}</span>
<span className="text-white/40 text-xs">· {article.readTime} de lecture</span>
<span className="text-white/40 text-xs">{post.date}</span>
<span className="text-white/40 text-xs">· {post.readTime} de lecture</span>
</div>
<h1 className="text-2xl md:text-4xl font-bold text-white leading-tight">
{article.titre}
{post.titre}
</h1>
</ScrollReveal>
</div>
@@ -178,7 +126,7 @@ export default async function BlogArticlePage({ params }: Props) {
</div>
<div className="space-y-5 text-text leading-relaxed">
{article.contenu.map((para, i) => (
{contenu.map((para, i) => (
<p key={i} className="text-base text-text-light">
{para.split(/(\*\*[^*]+\*\*)/).map((part, j) => {
if (part.startsWith("**") && part.endsWith("**")) {

View File

@@ -3,74 +3,23 @@ import Link from "next/link";
import Navbar from "@/components/marketing/Navbar";
import Footer from "@/components/marketing/Footer";
import ScrollReveal from "@/components/animations/ScrollReveal";
import { getBlogPosts, getSiteConfig } from "@/lib/content";
export const metadata: Metadata = {
export async function generateMetadata(): Promise<Metadata> {
const config = await getSiteConfig();
return {
title: "Blog Maçonnerie & Construction | Conseils OBC Maçonnerie",
description:
"Conseils, guides et actualités sur la construction de maison, la rénovation et le gros œuvre dans le Nord (59). Blog OBC Maçonnerie par Benoît Colin.",
alternates: { canonical: "https://obc-maconnerie.fr/blog" },
alternates: { canonical: `${config.url}/blog` },
};
const articles = [
{
slug: "combien-coute-construction-maison-nord",
titre: "Combien coûte la construction d'une maison dans le Nord en 2025 ?",
extrait:
"Budget, matériaux, terrain, main-d'œuvre — tout ce qu'il faut savoir pour estimer le coût de votre construction neuve dans le Nord.",
cat: "Construction",
date: "15 février 2025",
readTime: "6 min",
},
{
slug: "etapes-renovation-maison-ancienne",
titre: "Les étapes clés d'une rénovation de maison ancienne",
extrait:
"Vous avez acheté une maison ancienne dans le Nord et vous voulez la rénover ? Voici les étapes indispensables pour réussir votre projet.",
cat: "Rénovation",
date: "8 janvier 2025",
readTime: "5 min",
},
{
slug: "assainissement-non-collectif-obligations",
titre: "Assainissement non collectif : vos obligations légales",
extrait:
"Contrôle SPANC, mise aux normes, vente immobilière — tout ce que vous devez savoir sur l'assainissement non collectif.",
cat: "Assainissement",
date: "20 décembre 2024",
readTime: "4 min",
},
{
slug: "ossature-bois-avantages",
titre: "Ossature bois : pourquoi choisir ce mode constructif ?",
extrait:
"Légèreté, performance thermique, rapidité de construction — l'ossature bois a de nombreux avantages. OBC Maçonnerie vous explique.",
cat: "Construction",
date: "5 novembre 2024",
readTime: "5 min",
},
{
slug: "travaux-renovation-sans-permis-construction",
titre: "Quels travaux de rénovation ne nécessitent pas de permis ?",
extrait:
"Permis de construire, déclaration préalable, simple déclaration — on vous explique les règles selon la nature de vos travaux.",
cat: "Rénovation",
date: "18 octobre 2024",
readTime: "4 min",
},
{
slug: "fondations-maison-quels-types",
titre: "Les différents types de fondations pour une maison",
extrait:
"Semelles filantes, radier, pieux — quelles fondations choisir selon votre terrain et votre projet de construction ?",
cat: "Construction",
date: "2 septembre 2024",
readTime: "5 min",
},
];
}
const cats = ["Tous", "Construction", "Rénovation", "Assainissement"];
export default function BlogPage() {
export default async function BlogPage() {
const articles = await getBlogPosts();
return (
<main id="main-content" className="min-h-screen">
<Navbar />

View File

@@ -7,7 +7,7 @@ export const metadata: Metadata = {
title: "Conditions Générales de Vente | OBC Maçonnerie",
description:
"Conditions générales de vente d'OBC Maçonnerie — Benoît Colin, maçon à Mouchin (59310). Prestations de construction, rénovation et gros œuvre.",
alternates: { canonical: "https://obc-maconnerie.fr/cgv" },
alternates: { canonical: "https://obc-terrassement.fr/cgv" },
robots: { index: false, follow: false },
};

View File

@@ -2,12 +2,13 @@ import type { Metadata } from "next";
import Link from "next/link";
import Navbar from "@/components/marketing/Navbar";
import Footer from "@/components/marketing/Footer";
import { siteConfig } from "@/lib/site-config";
export const metadata: Metadata = {
title: "Politique de Confidentialité | OBC Maçonnerie",
description:
"Politique de confidentialité et protection des données personnelles du site OBC Maçonnerie, conformément au RGPD.",
alternates: { canonical: "https://obc-maconnerie.fr/confidentialite" },
alternates: { canonical: "https://obc-terrassement.fr/confidentialite" },
robots: { index: false, follow: false },
};
@@ -34,8 +35,8 @@ export default function Confidentialite() {
<p><strong className="text-text">Benoît COLIN OBC Maçonnerie</strong></p>
<p>SIREN : 531 827 871</p>
<p>221 Route de Saint-Amand, 59310 Mouchin</p>
<p>Tél : <a href="tel:0674453089" className="text-orange hover:underline">06 74 45 30 89</a></p>
<p>Email : <a href="mailto:contact@obc-maconnerie.fr" className="text-orange hover:underline">contact@obc-maconnerie.fr</a></p>
<p>Tél : <a href={`tel:${siteConfig.phoneRaw}`} className="text-orange hover:underline">{siteConfig.phone}</a></p>
<p>Email : <a href="mailto:contact@obc-terrassement.fr" className="text-orange hover:underline">contact@obc-terrassement.fr</a></p>
</div>
</section>
@@ -100,8 +101,8 @@ export default function Confidentialite() {
Conformément au RGPD, vous disposez d&apos;un droit d&apos;accès, de rectification, d&apos;effacement et de portabilité de vos données. Pour exercer ces droits, contactez-nous :
</p>
<p className="mt-3">
<a href="mailto:contact@obc-maconnerie.fr" className="text-orange font-semibold hover:underline">
contact@obc-maconnerie.fr
<a href="mailto:contact@obc-terrassement.fr" className="text-orange font-semibold hover:underline">
contact@obc-terrassement.fr
</a>
</p>
</section>

View File

@@ -6,7 +6,7 @@ export const metadata: Metadata = {
description:
"OBC Maçonnerie intervient à Douai pour vos travaux de construction de maison, rénovation et gros œuvre. Benoît Colin, maçon expert. Devis gratuit.",
keywords: ["construction maison Douai", "maçon Douai", "rénovation Douai", "gros oeuvre Douai", "maçon rénovation Douai"],
alternates: { canonical: "https://obc-maconnerie.fr/construction-maison-douai" },
alternates: { canonical: "https://obc-terrassement.fr/construction-maison-douai" },
};
export default function ConstructionMaisonDouaiPage() {

View File

@@ -6,7 +6,7 @@ export const metadata: Metadata = {
description:
"OBC Maçonnerie intervient à Orchies pour vos travaux de construction de maison, rénovation et gros œuvre. Benoît Colin, maçon expert. Devis gratuit.",
keywords: ["construction maison Orchies", "maçon Orchies", "rénovation Orchies", "gros oeuvre Orchies"],
alternates: { canonical: "https://obc-maconnerie.fr/construction-maison-orchies" },
alternates: { canonical: "https://obc-terrassement.fr/construction-maison-orchies" },
};
export default function ConstructionMaisonOrchiesPage() {

View File

@@ -6,7 +6,7 @@ export const metadata: Metadata = {
description:
"OBC Maçonnerie intervient à Valenciennes pour vos travaux de construction de maison, rénovation et gros œuvre. Benoît Colin, maçon expert. Devis gratuit.",
keywords: ["construction maison Valenciennes", "maçon Valenciennes", "rénovation Valenciennes", "gros oeuvre Valenciennes"],
alternates: { canonical: "https://obc-maconnerie.fr/construction-maison-valenciennes" },
alternates: { canonical: "https://obc-terrassement.fr/construction-maison-valenciennes" },
};
export default function ConstructionMaisonValenciennesPage() {

View File

@@ -4,8 +4,12 @@ import Navbar from "@/components/marketing/Navbar";
import Footer from "@/components/marketing/Footer";
import ScrollReveal from "@/components/animations/ScrollReveal";
import ContactForm from "@/components/marketing/ContactForm";
import { getSiteConfig } from "@/lib/content";
export async function generateMetadata(): Promise<Metadata> {
const config = await getSiteConfig();
return {
export const metadata: Metadata = {
title: "Construction de Maison dans le Nord | OBC Maçonnerie Orchies",
description:
"Construction neuve, fondations, ossature bois dans le Nord (59). OBC Maçonnerie vous accompagne de A à Z. Devis gratuit.",
@@ -17,8 +21,9 @@ export const metadata: Metadata = {
"construction maison Douai",
"construction maison Valenciennes",
],
alternates: { canonical: "https://obc-maconnerie.fr/construction-maison" },
alternates: { canonical: `${config.url}/construction-maison` },
};
}
const etapes = [
{ num: "01", title: "Étude & conseil", desc: "Benoît analyse votre terrain, votre plan et vos envies. Il adapte si besoin les plans d'architecte et vous conseille sur les matériaux." },
@@ -29,7 +34,9 @@ const etapes = [
{ num: "06", title: "Remise des clés", desc: "Livraison de votre maison dans les délais convenus, avec un chantier propre et soigné." },
];
export default function ConstructionMaisonPage() {
export default async function ConstructionMaisonPage() {
const config = await getSiteConfig();
const { phone, phoneRaw } = config;
return (
<main id="main-content" className="min-h-screen">
<Navbar />
@@ -56,9 +63,7 @@ export default function ConstructionMaisonPage() {
<Link href="/contact" className="inline-flex items-center justify-center gap-2 bg-orange hover:bg-orange-hover text-white font-bold px-7 py-3.5 rounded-xl transition-colors pulse-glow">
Demander un devis gratuit
</Link>
<a href="tel:0674453089" className="inline-flex items-center justify-center gap-2 bg-white/10 hover:bg-white/20 text-white font-semibold px-7 py-3.5 rounded-xl transition-colors border border-white/20">
06 74 45 30 89
</a>
<a href={`tel:${phoneRaw}`} className="inline-flex items-center justify-center gap-2 bg-white/10 hover:bg-white/20 text-white font-semibold px-7 py-3.5 rounded-xl transition-colors border border-white/20">{phone}</a>
</div>
</ScrollReveal>
</div>

View File

@@ -3,50 +3,46 @@ import Navbar from "@/components/marketing/Navbar";
import Footer from "@/components/marketing/Footer";
import ScrollReveal from "@/components/animations/ScrollReveal";
import ContactForm from "@/components/marketing/ContactForm";
import { getSiteConfig } from "@/lib/content";
export const metadata: Metadata = {
export async function generateMetadata(): Promise<Metadata> {
const config = await getSiteConfig();
return {
title: "Contact & Devis Gratuit | OBC Maçonnerie Nord",
description:
"Contactez OBC Maçonnerie pour un devis gratuit. Benoît Colin intervient à Orchies, Douai, Valenciennes et dans un rayon de 30km autour de Mouchin (59).",
alternates: { canonical: "https://obc-maconnerie.fr/contact" },
alternates: { canonical: `${config.url}/contact` },
};
}
export default async function ContactPage() {
const config = await getSiteConfig();
const { phone, phoneRaw, email, address, zones, zoneDescription } = config;
const infos = [
{
icon: "📞",
titre: "Téléphone",
val: "06 74 45 30 89",
href: "tel:0674453089",
val: phone,
href: `tel:${phoneRaw}`,
desc: "LunVen 7h19h",
},
{
icon: "📍",
titre: "Adresse",
val: "221 Route de Saint-Amand, 59310 Mouchin",
href: undefined,
val: address,
href: undefined as string | undefined,
desc: "Rayon d'intervention : 30km",
},
{
icon: "📧",
titre: "Email",
val: "contact@obc-maconnerie.fr",
href: "mailto:contact@obc-maconnerie.fr",
val: email,
href: `mailto:${email}`,
desc: "Réponse sous 24h",
},
];
const zones = [
"Orchies",
"Mouchin",
"Flines-lès-Raches",
"Château-l'Abbaye",
"Mérignies",
"Douai",
"Valenciennes",
"Saint-Amand-les-Eaux",
];
export default function ContactPage() {
return (
<main id="main-content" className="min-h-screen">
<Navbar />
@@ -100,11 +96,11 @@ export default function ContactPage() {
))}
</div>
<p className="text-text-muted text-xs italic">
Et toutes les communes dans un rayon de 20-30 km autour de Mouchin (Nord 59).
Et toutes les communes dans un rayon de {zoneDescription}.
</p>
<div className="mt-8 bg-navy rounded-2xl p-6">
<h3 className="text-white font-bold mb-2">Devis gratuit & sans engagement</h3>
<h3 className="text-white font-bold mb-2">Devis gratuit &amp; sans engagement</h3>
<p className="text-white/60 text-sm">
Benoît se déplace sur votre chantier pour évaluer votre projet, vous conseiller et vous remettre un devis clair et détaillé. Gratuit et sans engagement.
</p>

View File

@@ -4,8 +4,12 @@ import Navbar from "@/components/marketing/Navbar";
import Footer from "@/components/marketing/Footer";
import ScrollReveal from "@/components/animations/ScrollReveal";
import ContactForm from "@/components/marketing/ContactForm";
import { getSiteConfig } from "@/lib/content";
export async function generateMetadata(): Promise<Metadata> {
const config = await getSiteConfig();
return {
export const metadata: Metadata = {
title: "Création d'Accès, Voiries & Entrées | OBC Maçonnerie Nord",
description:
"Création d'accès, voiries privées, entrées de propriété et chemins dans le Nord (59). OBC Maçonnerie à Orchies. Devis gratuit.",
@@ -17,8 +21,9 @@ export const metadata: Metadata = {
"béton imprimé Nord",
"création accès Orchies",
],
alternates: { canonical: "https://obc-maconnerie.fr/creation-acces" },
alternates: { canonical: `${config.url}/creation-acces` },
};
}
const types = [
{ icon: "🚗", title: "Entrées de propriété", desc: "Création d'une entrée soignée en béton, béton imprimé, pavés ou gravier stabilisé — adaptée à votre maison." },
@@ -29,7 +34,9 @@ const types = [
{ icon: "💧", title: "Drainage & évacuation", desc: "Mise en place de caniveaux, avaloirs et systèmes de drainage pour éviter les accumulations d'eau." },
];
export default function CreationAccesPage() {
export default async function CreationAccesPage() {
const config = await getSiteConfig();
const { phone, phoneRaw } = config;
return (
<main id="main-content" className="min-h-screen">
<Navbar />
@@ -55,9 +62,7 @@ export default function CreationAccesPage() {
<Link href="/contact" className="inline-flex items-center justify-center gap-2 bg-orange hover:bg-orange-hover text-white font-bold px-7 py-3.5 rounded-xl transition-colors pulse-glow">
Demander un devis gratuit
</Link>
<a href="tel:0674453089" className="inline-flex items-center justify-center gap-2 bg-white/10 hover:bg-white/20 text-white font-semibold px-7 py-3.5 rounded-xl transition-colors border border-white/20">
06 74 45 30 89
</a>
<a href={`tel:${phoneRaw}`} className="inline-flex items-center justify-center gap-2 bg-white/10 hover:bg-white/20 text-white font-semibold px-7 py-3.5 rounded-xl transition-colors border border-white/20">{phone}</a>
</div>
</ScrollReveal>
</div>

View File

@@ -4,8 +4,12 @@ import Navbar from "@/components/marketing/Navbar";
import Footer from "@/components/marketing/Footer";
import ScrollReveal from "@/components/animations/ScrollReveal";
import ContactForm from "@/components/marketing/ContactForm";
import { getSiteConfig } from "@/lib/content";
export async function generateMetadata(): Promise<Metadata> {
const config = await getSiteConfig();
return {
export const metadata: Metadata = {
title: "Démolition Maison Nord 59 | OBC Maçonnerie",
description:
"Démolition totale ou partielle de maison, murs porteurs, bâtiments dans le Nord (59). OBC Maçonnerie à Orchies. Toutes garanties de sécurité. Devis gratuit.",
@@ -17,8 +21,9 @@ export const metadata: Metadata = {
"démolition Orchies",
"démolition Douai",
],
alternates: { canonical: "https://obc-maconnerie.fr/demolition" },
alternates: { canonical: `${config.url}/demolition` },
};
}
const types = [
{ icon: "🏚️", title: "Démolition totale", desc: "Destruction complète d'un bâtiment résidentiel ou annexe, avec évacuation des gravats et remise en état du terrain." },
@@ -29,7 +34,9 @@ const types = [
{ icon: "🏠", title: "Curage intérieur", desc: "Enlèvement complet des éléments intérieurs (cloisons, planchers, revêtements) avant une rénovation lourde." },
];
export default function DemolitionPage() {
export default async function DemolitionPage() {
const config = await getSiteConfig();
const { phone, phoneRaw } = config;
return (
<main id="main-content" className="min-h-screen">
<Navbar />
@@ -55,9 +62,7 @@ export default function DemolitionPage() {
<Link href="/contact" className="inline-flex items-center justify-center gap-2 bg-orange hover:bg-orange-hover text-white font-bold px-7 py-3.5 rounded-xl transition-colors pulse-glow">
Demander un devis gratuit
</Link>
<a href="tel:0674453089" className="inline-flex items-center justify-center gap-2 bg-white/10 hover:bg-white/20 text-white font-semibold px-7 py-3.5 rounded-xl transition-colors border border-white/20">
06 74 45 30 89
</a>
<a href={`tel:${phoneRaw}`} className="inline-flex items-center justify-center gap-2 bg-white/10 hover:bg-white/20 text-white font-semibold px-7 py-3.5 rounded-xl transition-colors border border-white/20">{phone}</a>
</div>
</ScrollReveal>
</div>

View File

@@ -1,8 +1,9 @@
import type { Metadata } from "next";
import CookieBanner from "@/components/CookieBanner";
import { siteConfig } from "@/lib/site-config";
import "./globals.css";
const BASE_URL = process.env.NEXT_PUBLIC_APP_URL || "https://obc-maconnerie.fr";
const BASE_URL = process.env.NEXT_PUBLIC_APP_URL || siteConfig.url;
export const metadata: Metadata = {
metadataBase: new URL(BASE_URL),
@@ -95,8 +96,8 @@ export default function RootLayout({
name: "OBC Maçonnerie",
description:
"Construction de maison, rénovation, assainissement et gros œuvre dans le Nord",
telephone: "06 74 45 30 89",
email: "contact@obc-maconnerie.fr",
telephone: siteConfig.phone,
email: siteConfig.email,
url: BASE_URL,
logo: `${BASE_URL}/icon-512.svg`,
image: `${BASE_URL}/og-image.jpg`,
@@ -143,7 +144,7 @@ export default function RootLayout({
},
contactPoint: {
"@type": "ContactPoint",
telephone: "06 74 45 30 89",
telephone: siteConfig.phone,
contactType: "customer service",
availableLanguage: "French",
},

View File

@@ -6,7 +6,7 @@ export const metadata: Metadata = {
description:
"OBC Maçonnerie intervient à Flines-lès-Raches pour vos travaux de construction, rénovation et gros œuvre. Benoît Colin, maçon expert. Devis gratuit.",
keywords: ["maçon Flines-lès-Raches", "construction Flines Raches", "rénovation Flines Raches", "maçon Flines Nord"],
alternates: { canonical: "https://obc-maconnerie.fr/macon-flines-lez-raches" },
alternates: { canonical: "https://obc-terrassement.fr/macon-flines-lez-raches" },
};
export default function MaconFlinesPage() {

View File

@@ -6,7 +6,7 @@ export const metadata: Metadata = {
description:
"OBC Maçonnerie est basée à Mouchin (59310). Benoît Colin, maçon expert local. Construction, rénovation, assainissement, gros œuvre. Devis gratuit.",
keywords: ["maçon Mouchin", "entreprise maçonnerie Mouchin", "construction Mouchin", "rénovation Mouchin"],
alternates: { canonical: "https://obc-maconnerie.fr/macon-mouchin" },
alternates: { canonical: "https://obc-terrassement.fr/macon-mouchin" },
};
export default function MaconMouchinPage() {

View File

@@ -6,7 +6,7 @@ export const metadata: Metadata = {
description:
"OBC Maçonnerie intervient à Saint-Amand-les-Eaux pour vos travaux de construction, rénovation, assainissement et gros œuvre. Devis gratuit.",
keywords: ["maçon Saint-Amand-les-Eaux", "construction Saint-Amand", "rénovation Saint-Amand les Eaux", "maçon Saint-Amand Nord"],
alternates: { canonical: "https://obc-maconnerie.fr/macon-saint-amand-les-eaux" },
alternates: { canonical: "https://obc-terrassement.fr/macon-saint-amand-les-eaux" },
};
export default function MaconSaintAmandPage() {

View File

@@ -2,12 +2,13 @@ import type { Metadata } from "next";
import Link from "next/link";
import Navbar from "@/components/marketing/Navbar";
import Footer from "@/components/marketing/Footer";
import { siteConfig } from "@/lib/site-config";
export const metadata: Metadata = {
title: "Mentions Légales | OBC Maçonnerie",
description:
"Mentions légales du site OBC Maçonnerie — Benoît Colin, maçon à Mouchin (59310). SIREN 531 827 871.",
alternates: { canonical: "https://obc-maconnerie.fr/mentions-legales" },
alternates: { canonical: "https://obc-terrassement.fr/mentions-legales" },
robots: { index: false, follow: false },
};
@@ -31,7 +32,7 @@ export default function MentionsLegales() {
<div className="space-y-10 text-text-light text-sm leading-relaxed">
<p className="italic text-text-muted">
Conformément aux dispositions de la loi n° 2004-575 du 21 juin 2004 pour la confiance en l&apos;économie numérique (LCEN), voici les informations légales du site <strong className="text-text">obc-maconnerie.fr</strong>.
Conformément aux dispositions de la loi n° 2004-575 du 21 juin 2004 pour la confiance en l&apos;économie numérique (LCEN), voici les informations légales du site <strong className="text-text">obc-terrassement.fr</strong>.
</p>
<section>
@@ -43,8 +44,8 @@ export default function MentionsLegales() {
<li><strong className="text-text">Statut :</strong> Entreprise individuelle</li>
<li><strong className="text-text">SIREN :</strong> 531 827 871</li>
<li><strong className="text-text">Siège social :</strong> 221 Route de Saint-Amand, 59310 Mouchin, France</li>
<li><strong className="text-text">Téléphone :</strong> <a href="tel:0674453089" className="text-orange hover:underline">06 74 45 30 89</a></li>
<li><strong className="text-text">Email :</strong> <a href="mailto:contact@obc-maconnerie.fr" className="text-orange hover:underline">contact@obc-maconnerie.fr</a></li>
<li><strong className="text-text">Téléphone :</strong> <a href={`tel:${siteConfig.phoneRaw}`} className="text-orange hover:underline">{siteConfig.phone}</a></li>
<li><strong className="text-text">Email :</strong> <a href="mailto:contact@obc-terrassement.fr" className="text-orange hover:underline">contact@obc-terrassement.fr</a></li>
</ul>
<p className="mt-3"><strong className="text-text">Directeur de la publication :</strong> Benoît COLIN</p>
</div>

View File

@@ -4,181 +4,53 @@ import Navbar from "@/components/marketing/Navbar";
import Footer from "@/components/marketing/Footer";
import ScrollReveal from "@/components/animations/ScrollReveal";
import ContactForm from "@/components/marketing/ContactForm";
import {
getSiteConfig,
getServices,
getTestimonials,
getFAQ,
getValues,
getPartners,
getRealisations,
} from "@/lib/content";
import type { Service, Testimonial, FAQItem } from "@/types/content";
export const metadata: Metadata = {
title: "OBC Maçonnerie | Constructeur & Maçon à Orchies (Nord 59)",
description:
"Benoît Colin, maçon expert à Mouchin. Construction de maison, rénovation, assainissement et gros œuvre dans un rayon de 30km autour d'Orchies. Devis gratuit.",
alternates: {
canonical: "https://obc-maconnerie.fr",
},
export async function generateMetadata(): Promise<Metadata> {
const config = await getSiteConfig();
return {
title: config.seo.title,
description: config.seo.description,
alternates: { canonical: config.url },
};
}
const services = [
{
icon: "🏠",
title: "Construction de maison",
desc: "Fondations, ossature bois, gros œuvre — on bâtit votre projet de A à Z avec vous.",
href: "/construction-maison",
},
{
icon: "🔨",
title: "Rénovation",
desc: "Maison ou appartement, on s'adapte à votre projet et vos envies.",
href: "/renovation",
},
{
icon: "💧",
title: "Assainissement",
desc: "Mise aux normes et création de systèmes d'assainissement fiables.",
href: "/assainissement",
},
{
icon: "🚧",
title: "Création d'accès",
desc: "Voiries, entrées, chemins — on crée vos accès sur mesure.",
href: "/creation-acces",
},
{
icon: "🏗️",
title: "Démolition",
desc: "Démolition totale ou partielle, avec toutes les garanties de sécurité.",
href: "/demolition",
},
{
icon: "🤝",
title: "Conseil & Accompagnement",
desc: "Benoît vous éclaire dans vos choix : matériaux, plans, adaptations — on réfléchit ensemble.",
href: "/contact",
},
];
const pilliers = [
{
icon: "📍",
title: "Proche de vous",
desc: "Disponible, à l'écoute, Benoît intervient dans votre secteur local et prend le temps de comprendre votre projet.",
},
{
icon: "💡",
title: "Conseil expert",
desc: "Il guide vos choix de matériaux et adapte les plans d'architecte pour un résultat qui vous ressemble.",
},
{
icon: "🛡️",
title: "Acteur de confiance",
desc: "Transparent à chaque étape, Benoît rassure, explique et vous tient informé de l'avancement du chantier.",
},
{
icon: "❤️",
title: "Passionné du métier",
desc: "\"On ne fait jamais deux fois la même maison.\" Benoît aime être au cœur de chaque projet, de A à Z.",
},
];
const partenaires = [
{ label: "Électricité", icon: "⚡" },
{ label: "Plomberie", icon: "🔧" },
{ label: "Charpente", icon: "🪵" },
{ label: "Couverture", icon: "🏚️" },
{ label: "Isolation", icon: "🧱" },
{ label: "Menuiserie", icon: "🚪" },
{ label: "Carrelage", icon: "🔳" },
{ label: "Peinture", icon: "🎨" },
];
const villes = [
"Orchies",
"Mouchin",
"Flines-lès-Raches",
"Château-l'Abbaye",
"Mérignies",
"Douai",
"Valenciennes",
"Saint-Amand-les-Eaux",
];
const realisations = [
{
title: "Construction d'une maison individuelle",
desc: "Fondations, gros œuvre et ossature — livraison clé en main à Orchies.",
cat: "Construction neuve",
color: "bg-navy",
},
{
title: "Rénovation complète d'une maison de ville",
desc: "Restructuration intérieure, cloisons, escalier réhabilité à Douai.",
cat: "Rénovation",
color: "bg-stone",
},
{
title: "Création d'un accès et chemin d'entrée",
desc: "Voirie et entrée béton imprimé, aménagement paysager à Mérignies.",
cat: "Création d'accès",
color: "bg-orange",
},
];
const temoignages = [
{
nom: "Christophe & Marie L.",
lieu: "Orchies",
projet: "Construction maison",
texte:
"Benoît nous a accompagnés de A à Z dans la construction de notre maison. Il a su adapter le plan d'architecte à nos envies tout en respectant notre budget. Disponible, professionnel, et vraiment à l'écoute. On recommande les yeux fermés.",
note: 5,
},
{
nom: "Sophie D.",
lieu: "Douai",
projet: "Rénovation",
texte:
"On lui a confié la rénovation complète de notre maison de 1970. Benoît a pris le temps de tout nous expliquer, a proposé des solutions auxquelles on n'avait pas pensé, et le résultat est magnifique. Un vrai professionnel.",
note: 5,
},
{
nom: "Famille Moreau",
lieu: "Saint-Amand-les-Eaux",
projet: "Assainissement",
texte:
"Mise aux normes de notre système d'assainissement réalisée dans les délais et en toute transparence. Benoît nous a expliqué chaque étape. Très sérieux et propre dans son travail.",
note: 5,
},
];
const faqs = [
{
q: "Dans quelle zone intervenez-vous ?",
a: "OBC Maçonnerie intervient dans un rayon de 20 à 30 km autour de Mouchin (59310) : Orchies, Flines-lès-Raches, Château-l'Abbaye, Mérignies, Douai, Valenciennes, Saint-Amand-les-Eaux et les communes alentour.",
},
{
q: "Faites-vous des devis gratuits ?",
a: "Oui, absolument. Le devis est gratuit et sans engagement. Contactez Benoît par téléphone ou via le formulaire, il se déplace pour évaluer votre projet.",
},
{
q: "Pouvez-vous adapter un plan d'architecte ?",
a: "Oui, c'est même l'une de nos spécialités. Benoît collabore directement avec vous pour adapter les plans à vos envies, votre budget et les contraintes du terrain.",
},
{
q: "Combien de temps dure une construction de maison ?",
a: "Une construction neuve prend en moyenne 10 à 18 mois selon la complexité du projet, les conditions météo et les délais de livraison des matériaux. Benoît vous donne un calendrier dès la signature.",
},
{
q: "Travaillez-vous avec d'autres artisans ?",
a: "Oui. OBC Maçonnerie dispose d'un réseau de partenaires de confiance pour tous les corps de métier : électricité, plomberie, charpente, isolation, menuiserie, carrelage, peinture et couverture. Vous avez un seul interlocuteur pour coordonner l'ensemble.",
},
];
function ServiceCard({ service }: { service: Service }) {
const href = service.slug === "conseil" ? "/contact" : `/${service.slug}`;
return (
<Link
href={href}
className="group block bg-bg-white border border-border rounded-2xl p-6 hover:border-orange hover:shadow-lg transition-all duration-300 card-hover"
>
<div className="text-3xl mb-4">{service.icon}</div>
<h3 className="text-navy font-bold text-lg mb-2 group-hover:text-orange transition-colors">
{service.title}
</h3>
<p className="text-text-light text-sm leading-relaxed">{service.shortDescription}</p>
<div className="mt-4 flex items-center gap-1 text-orange text-sm font-semibold">
En savoir plus
<svg className="w-4 h-4 group-hover:translate-x-1 transition-transform" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M17 8l4 4m0 0l-4 4m4-4H3" />
</svg>
</div>
</Link>
);
}
function StarRating({ note }: { note: number }) {
return (
<div className="flex gap-0.5">
{Array.from({ length: 5 }).map((_, i) => (
<svg
key={i}
className={`w-4 h-4 ${i < note ? "text-orange" : "text-border"}`}
fill="currentColor"
viewBox="0 0 20 20"
>
<svg key={i} className={`w-4 h-4 ${i < note ? "text-orange" : "text-border"}`} fill="currentColor" viewBox="0 0 20 20">
<path d="M9.049 2.927c.3-.921 1.603-.921 1.902 0l1.07 3.292a1 1 0 00.95.69h3.462c.969 0 1.371 1.24.588 1.81l-2.8 2.034a1 1 0 00-.364 1.118l1.07 3.292c.3.921-.755 1.688-1.54 1.118l-2.8-2.034a1 1 0 00-1.175 0l-2.8 2.034c-.784.57-1.838-.197-1.539-1.118l1.07-3.292a1 1 0 00-.364-1.118L2.98 8.72c-.783-.57-.38-1.81.588-1.81h3.461a1 1 0 00.951-.69l1.07-3.292z" />
</svg>
))}
@@ -186,68 +58,90 @@ function StarRating({ note }: { note: number }) {
);
}
export default function HomePage() {
function TestimonialCard({ t }: { t: Testimonial }) {
const serviceLabel: Record<string, string> = {
"construction-maison": "Construction de maison",
renovation: "Rénovation",
assainissement: "Assainissement",
"creation-acces": "Création d'accès",
demolition: "Démolition",
};
return (
<div className="bg-white/5 border border-white/10 rounded-2xl p-6 h-full flex flex-col">
<StarRating note={t.rating} />
<p className="text-white/80 text-sm leading-relaxed mt-4 flex-1 italic">&ldquo;{t.text}&rdquo;</p>
<div className="mt-5 pt-4 border-t border-white/10">
<p className="text-white font-semibold text-sm">{t.name}</p>
<p className="text-white/40 text-xs">{t.ville} {serviceLabel[t.service] ?? t.service}</p>
</div>
</div>
);
}
function FAQAccordion({ item }: { item: FAQItem }) {
return (
<details className="group bg-bg-white border border-border rounded-2xl overflow-hidden">
<summary className="flex items-center justify-between px-6 py-4 cursor-pointer font-semibold text-navy hover:text-orange transition-colors list-none">
{item.question}
<svg className="w-5 h-5 text-text-muted group-open:rotate-180 transition-transform shrink-0 ml-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M19 9l-7 7-7-7" />
</svg>
</summary>
<div className="px-6 pb-5 text-text-light text-sm leading-relaxed border-t border-border-light pt-4">
{item.answer}
</div>
</details>
);
}
export default async function HomePage() {
const [config, services, testimonials, faqItems, values, partners, realisations] =
await Promise.all([
getSiteConfig(),
getServices(),
getTestimonials(),
getFAQ(),
getValues(),
getPartners(),
getRealisations(),
]);
const { hero, zones, zoneDescription, partnersTitle, partnersMessage, phone, phoneRaw } = config;
return (
<main id="main-content" className="min-h-screen">
<Navbar />
{/* ── SECTION 1 — HERO ── */}
<section className="relative bg-navy overflow-hidden pt-20 pb-24 md:pt-28 md:pb-32">
{/* Background texture */}
<div className="absolute inset-0 opacity-5">
<div
className="absolute inset-0"
style={{
backgroundImage:
"repeating-linear-gradient(45deg, #fff 0, #fff 1px, transparent 0, transparent 50%)",
backgroundSize: "20px 20px",
}}
/>
</div>
<div className="absolute inset-0 opacity-5" style={{ backgroundImage: "repeating-linear-gradient(45deg,#fff 0,#fff 1px,transparent 0,transparent 50%)", backgroundSize: "20px 20px" }} />
<div className="relative max-w-5xl mx-auto px-4 sm:px-6 lg:px-8 text-center">
{/* Badge */}
<div className="inline-flex items-center gap-2 bg-white/10 border border-white/20 rounded-full px-4 py-1.5 mb-6 animate-hero-text-1">
<div className="inline-flex items-center gap-2 bg-white/10 border border-white/20 rounded-full px-4 py-1.5 mb-6">
<span className="w-2 h-2 bg-green-400 rounded-full animate-pulse" />
<span className="text-white/80 text-sm">
Disponible, à l&apos;écoute Benoît vous accompagne de la première pierre à la remise des clés
</span>
<span className="text-white/80 text-sm">{hero.badge}</span>
</div>
<h1 className="text-4xl md:text-6xl font-bold text-white leading-tight mb-6 animate-hero-text-2">
<h1 className="text-4xl md:text-6xl font-bold text-white leading-tight mb-6">
Maçon &amp; Constructeur<br />
<span className="text-orange">dans le Nord</span>
</h1>
<p className="text-white/70 text-lg md:text-xl max-w-2xl mx-auto mb-8 animate-hero-text-3">
Construction de maison, rénovation, assainissement et gros œuvre
expertise autour d&apos;Orchies, Douai et Valenciennes.
</p>
<p className="text-white/70 text-lg md:text-xl max-w-2xl mx-auto mb-8">{hero.subtitle}</p>
<div className="flex flex-col sm:flex-row gap-4 justify-center animate-hero-text-3">
<Link
href="/contact"
className="inline-flex items-center justify-center gap-2 bg-orange hover:bg-orange-hover text-white font-bold px-8 py-4 rounded-xl text-base transition-colors pulse-glow"
>
Demander un devis gratuit
<div className="flex flex-col sm:flex-row gap-4 justify-center">
<Link href="/contact" className="inline-flex items-center justify-center gap-2 bg-orange hover:bg-orange-hover text-white font-bold px-8 py-4 rounded-xl text-base transition-colors pulse-glow">
{hero.cta}
<svg className="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M17 8l4 4m0 0l-4 4m4-4H3" />
</svg>
</Link>
<Link
href="/realisations"
className="inline-flex items-center justify-center gap-2 bg-white/10 hover:bg-white/20 text-white font-semibold px-8 py-4 rounded-xl text-base transition-colors border border-white/20"
>
Voir nos réalisations
<Link href="/realisations" className="inline-flex items-center justify-center gap-2 bg-white/10 hover:bg-white/20 text-white font-semibold px-8 py-4 rounded-xl text-base transition-colors border border-white/20">
{hero.ctaSecondary}
</Link>
</div>
{/* Stats */}
<div className="mt-14 grid grid-cols-3 gap-6 max-w-lg mx-auto border-t border-white/10 pt-10">
{[
{ val: "15+", label: "ans d'expérience" },
{ val: "200+", label: "chantiers réalisés" },
{ val: "30km", label: "de rayon d'action" },
].map((s) => (
{hero.stats.map((s) => (
<div key={s.label} className="text-center">
<div className="text-2xl md:text-3xl font-bold text-orange">{s.val}</div>
<div className="text-white/50 text-xs mt-1">{s.label}</div>
@@ -269,26 +163,10 @@ export default function HomePage() {
</p>
</div>
</ScrollReveal>
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-6">
{services.map((s, i) => (
<ScrollReveal key={s.title} direction="up" delay={i * 80}>
<Link
href={s.href}
className="group block bg-bg-white border border-border rounded-2xl p-6 hover:border-orange hover:shadow-lg transition-all duration-300 card-hover"
>
<div className="text-3xl mb-4">{s.icon}</div>
<h3 className="text-navy font-bold text-lg mb-2 group-hover:text-orange transition-colors">
{s.title}
</h3>
<p className="text-text-light text-sm leading-relaxed">{s.desc}</p>
<div className="mt-4 flex items-center gap-1 text-orange text-sm font-semibold">
En savoir plus
<svg className="w-4 h-4 group-hover:translate-x-1 transition-transform" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M17 8l4 4m0 0l-4 4m4-4H3" />
</svg>
</div>
</Link>
<ScrollReveal key={s.slug} direction="up" delay={i * 80}>
<ServiceCard service={s} />
</ScrollReveal>
))}
</div>
@@ -304,14 +182,13 @@ export default function HomePage() {
<h2 className="text-3xl md:text-4xl font-bold text-navy mt-2">Pourquoi choisir OBC Maçonnerie ?</h2>
</div>
</ScrollReveal>
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-6">
{pilliers.map((p, i) => (
<ScrollReveal key={p.title} direction="up" delay={i * 100}>
{values.map((v, i) => (
<ScrollReveal key={v.title} direction="up" delay={i * 100}>
<div className="bg-bg-white rounded-2xl p-6 border border-border text-center h-full">
<div className="text-4xl mb-4">{p.icon}</div>
<h3 className="text-navy font-bold text-lg mb-3">{p.title}</h3>
<p className="text-text-light text-sm leading-relaxed">{p.desc}</p>
<div className="text-4xl mb-4">{v.icon}</div>
<h3 className="text-navy font-bold text-lg mb-3">{v.title}</h3>
<p className="text-text-light text-sm leading-relaxed">{v.description}</p>
</div>
</ScrollReveal>
))}
@@ -325,17 +202,12 @@ export default function HomePage() {
<ScrollReveal direction="up">
<div className="text-center mb-12">
<span className="text-orange text-sm font-semibold uppercase tracking-widest">Un réseau solide</span>
<h2 className="text-3xl md:text-4xl font-bold text-navy mt-2">
Seul on va vite, ensemble on va plus loin.
</h2>
<p className="text-text-light mt-4 max-w-xl mx-auto">
Grâce à notre réseau de partenaires de confiance, nous coordonnons l&apos;ensemble des corps de métier pour que votre maison prenne forme de A à Z.
</p>
<h2 className="text-3xl md:text-4xl font-bold text-navy mt-2">{partnersTitle}</h2>
<p className="text-text-light mt-4 max-w-xl mx-auto">{partnersMessage}</p>
</div>
</ScrollReveal>
<div className="grid grid-cols-2 sm:grid-cols-4 gap-4">
{partenaires.map((p, i) => (
{partners.map((p, i) => (
<ScrollReveal key={p.label} direction="up" delay={i * 60}>
<div className="bg-bg-white border border-border rounded-xl p-4 text-center hover:border-orange hover:shadow-md transition-all">
<div className="text-2xl mb-2">{p.icon}</div>
@@ -344,16 +216,12 @@ export default function HomePage() {
</ScrollReveal>
))}
</div>
<ScrollReveal direction="up" delay={200}>
<div className="mt-10 bg-navy rounded-2xl p-6 md:p-8 text-center">
<p className="text-white text-base md:text-lg font-medium">
Un seul interlocuteur pour coordonner l&apos;ensemble de votre projet de la démolition à la remise des clés.
</p>
<Link
href="/partenaires"
className="inline-flex items-center gap-2 mt-4 text-orange-light hover:text-white font-semibold transition-colors"
>
<Link href="/partenaires" className="inline-flex items-center gap-2 mt-4 text-orange-light hover:text-white font-semibold transition-colors">
Découvrir notre réseau
<svg className="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M17 8l4 4m0 0l-4 4m4-4H3" />
@@ -369,33 +237,25 @@ export default function HomePage() {
<div className="max-w-5xl mx-auto px-4 sm:px-6 lg:px-8 text-center">
<ScrollReveal direction="up">
<span className="text-orange text-sm font-semibold uppercase tracking-widest">Secteur d&apos;activité</span>
<h2 className="text-3xl md:text-4xl font-bold text-navy mt-2 mb-4">
Nous intervenons dans toute la région
</h2>
<h2 className="text-3xl md:text-4xl font-bold text-navy mt-2 mb-4">Nous intervenons dans toute la région</h2>
<p className="text-text-light max-w-xl mx-auto mb-10">
OBC Maçonnerie intervient dans un rayon de 20 à 30 km autour de Mouchin (Nord 59).
OBC Maçonnerie intervient dans un rayon de {zoneDescription}.
</p>
</ScrollReveal>
<div className="flex flex-wrap justify-center gap-3 mb-8">
{villes.map((v, i) => (
{zones.map((v, i) => (
<ScrollReveal key={v} direction="up" delay={i * 50}>
<span className="inline-flex items-center gap-1.5 bg-bg-white border border-border text-navy font-medium text-sm px-4 py-2 rounded-full hover:border-orange hover:shadow-sm transition-all">
<span className="text-orange">📍</span>
{v}
<span className="text-orange">📍</span>{v}
</span>
</ScrollReveal>
))}
</div>
<ScrollReveal direction="up" delay={100}>
<p className="text-text-light text-sm italic">
Et dans toutes les communes à 20-30 km autour de Mouchin contactez-nous pour vérifier votre zone.
Et dans toutes les communes à {zoneDescription} contactez-nous pour vérifier votre zone.
</p>
<Link
href="/contact"
className="inline-flex items-center gap-2 mt-6 bg-orange hover:bg-orange-hover text-white font-bold px-7 py-3.5 rounded-xl transition-colors"
>
<Link href="/contact" className="inline-flex items-center gap-2 mt-6 bg-orange hover:bg-orange-hover text-white font-bold px-7 py-3.5 rounded-xl transition-colors">
Demander un devis dans ma commune
</Link>
</ScrollReveal>
@@ -411,34 +271,28 @@ export default function HomePage() {
<h2 className="text-3xl md:text-4xl font-bold text-navy mt-2">Aperçu de nos réalisations</h2>
</div>
</ScrollReveal>
<div className="grid grid-cols-1 md:grid-cols-3 gap-6">
{realisations.map((r, i) => (
{realisations.map((r, i) => {
const colors = ["bg-navy", "bg-stone", "bg-orange"];
return (
<ScrollReveal key={r.title} direction="up" delay={i * 100}>
<div className="bg-bg-white rounded-2xl overflow-hidden border border-border hover:shadow-lg transition-all group card-hover">
<div className={`${r.color} h-44 flex items-center justify-center`}>
<div className={`${colors[i % colors.length]} h-44 flex items-center justify-center`}>
<span className="text-white/20 text-8xl font-bold">{i + 1}</span>
</div>
<div className="p-5">
<span className="inline-block bg-bg-muted text-text-light text-xs font-semibold px-2 py-1 rounded-full mb-2">
{r.cat}
</span>
<h3 className="text-navy font-bold text-base mb-1 group-hover:text-orange transition-colors">
{r.title}
</h3>
<p className="text-text-light text-sm">{r.desc}</p>
<span className="inline-block bg-bg-muted text-text-light text-xs font-semibold px-2 py-1 rounded-full mb-2">{r.ville}</span>
<h3 className="text-navy font-bold text-base mb-1 group-hover:text-orange transition-colors">{r.title}</h3>
<p className="text-text-light text-sm">{r.description}</p>
</div>
</div>
</ScrollReveal>
))}
);
})}
</div>
<ScrollReveal direction="up" delay={150}>
<div className="text-center mt-8">
<Link
href="/realisations"
className="inline-flex items-center gap-2 border-2 border-navy text-navy hover:bg-navy hover:text-white font-bold px-7 py-3.5 rounded-xl transition-colors"
>
<Link href="/realisations" className="inline-flex items-center gap-2 border-2 border-navy text-navy hover:bg-navy hover:text-white font-bold px-7 py-3.5 rounded-xl transition-colors">
Voir toutes nos réalisations
<svg className="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M17 8l4 4m0 0l-4 4m4-4H3" />
@@ -458,20 +312,10 @@ export default function HomePage() {
<h2 className="text-3xl md:text-4xl font-bold text-white mt-2">Témoignages clients</h2>
</div>
</ScrollReveal>
<div className="grid grid-cols-1 md:grid-cols-3 gap-6">
{temoignages.map((t, i) => (
<ScrollReveal key={t.nom} direction="up" delay={i * 100}>
<div className="bg-white/5 border border-white/10 rounded-2xl p-6 h-full flex flex-col">
<StarRating note={t.note} />
<p className="text-white/80 text-sm leading-relaxed mt-4 flex-1 italic">
&ldquo;{t.texte}&rdquo;
</p>
<div className="mt-5 pt-4 border-t border-white/10">
<p className="text-white font-semibold text-sm">{t.nom}</p>
<p className="text-white/40 text-xs">{t.lieu} {t.projet}</p>
</div>
</div>
{testimonials.map((t, i) => (
<ScrollReveal key={t.name} direction="up" delay={i * 100}>
<TestimonialCard t={t} />
</ScrollReveal>
))}
</div>
@@ -487,26 +331,10 @@ export default function HomePage() {
<h2 className="text-3xl md:text-4xl font-bold text-navy mt-2">FAQ</h2>
</div>
</ScrollReveal>
<div className="space-y-4">
{faqs.map((f, i) => (
<ScrollReveal key={f.q} direction="up" delay={i * 60}>
<details className="group bg-bg-white border border-border rounded-2xl overflow-hidden">
<summary className="flex items-center justify-between px-6 py-4 cursor-pointer font-semibold text-navy hover:text-orange transition-colors list-none">
{f.q}
<svg
className="w-5 h-5 text-text-muted group-open:rotate-180 transition-transform shrink-0 ml-4"
fill="none"
stroke="currentColor"
viewBox="0 0 24 24"
>
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M19 9l-7 7-7-7" />
</svg>
</summary>
<div className="px-6 pb-5 text-text-light text-sm leading-relaxed border-t border-border-light pt-4">
{f.a}
</div>
</details>
{faqItems.map((f, i) => (
<ScrollReveal key={f.question} direction="up" delay={i * 60}>
<FAQAccordion item={f} />
</ScrollReveal>
))}
</div>
@@ -522,9 +350,7 @@ export default function HomePage() {
<h2 className="text-3xl md:text-4xl font-bold text-navy mt-2">Parlez-nous de votre projet</h2>
<p className="text-text-light mt-3">
Réponse sous 24h ou appelez directement Benoît au{" "}
<a href="tel:0674453089" className="text-orange font-bold hover:underline">
06 74 45 30 89
</a>
<a href={`tel:${phoneRaw}`} className="text-orange font-bold hover:underline">{phone}</a>
</p>
</div>
</ScrollReveal>

View File

@@ -3,58 +3,21 @@ import Link from "next/link";
import Navbar from "@/components/marketing/Navbar";
import Footer from "@/components/marketing/Footer";
import ScrollReveal from "@/components/animations/ScrollReveal";
import { getPartners, getSiteConfig } from "@/lib/content";
export const metadata: Metadata = {
export async function generateMetadata(): Promise<Metadata> {
const config = await getSiteConfig();
return {
title: "Notre Réseau de Partenaires | OBC Maçonnerie Nord",
description:
"OBC Maçonnerie coordonne un réseau d'artisans partenaires de confiance pour livrer votre maison de A à Z : électricité, plomberie, charpente, isolation, menuiserie, carrelage, peinture.",
alternates: { canonical: "https://obc-maconnerie.fr/partenaires" },
alternates: { canonical: `${config.url}/partenaires` },
};
}
const partenaires = [
{
icon: "⚡",
metier: "Électricité",
desc: "Installation électrique aux normes NF C 15-100, tableau de distribution, prises, éclairage.",
},
{
icon: "🔧",
metier: "Plomberie",
desc: "Plomberie sanitaire, chauffage central, installation de salles de bains et cuisines.",
},
{
icon: "🪵",
metier: "Charpente",
desc: "Charpente traditionnelle ou industrielle, structure bois pour combles aménageables ou non.",
},
{
icon: "🏚️",
metier: "Couverture",
desc: "Pose de toiture, tuiles, ardoises, zinc — étanchéité et finitions soignées.",
},
{
icon: "🧱",
metier: "Isolation",
desc: "Isolation thermique et phonique par l'intérieur ou l'extérieur, combles, planchers.",
},
{
icon: "🚪",
metier: "Menuiserie",
desc: "Fenêtres, portes, vérandas, volets — menuiserie bois, PVC ou aluminium.",
},
{
icon: "🔳",
metier: "Carrelage & Revêtements",
desc: "Pose de carrelage, parquet, faïence — pour sols et murs, intérieur et extérieur.",
},
{
icon: "🎨",
metier: "Peinture",
desc: "Peinture intérieure et extérieure, enduits décoratifs, ravalement de façade.",
},
];
export default async function PartenairesPage() {
const partenaires = await getPartners();
export default function PartenairesPage() {
return (
<main id="main-content" className="min-h-screen">
<Navbar />
@@ -88,10 +51,10 @@ export default function PartenairesPage() {
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-5">
{partenaires.map((p, i) => (
<ScrollReveal key={p.metier} direction="up" delay={i * 70}>
<ScrollReveal key={p.label} direction="up" delay={i * 70}>
<div className="bg-bg-white border border-border rounded-2xl p-5 text-center h-full hover:border-orange hover:shadow-md transition-all">
<div className="text-4xl mb-3">{p.icon}</div>
<h3 className="text-navy font-bold text-base mb-2">{p.metier}</h3>
<h3 className="text-navy font-bold text-base mb-2">{p.label}</h3>
<p className="text-text-light text-xs leading-relaxed">{p.desc}</p>
</div>
</ScrollReveal>

View File

@@ -3,62 +3,24 @@ import Link from "next/link";
import Navbar from "@/components/marketing/Navbar";
import Footer from "@/components/marketing/Footer";
import ScrollReveal from "@/components/animations/ScrollReveal";
import { getRealisations, getSiteConfig } from "@/lib/content";
export const metadata: Metadata = {
export async function generateMetadata(): Promise<Metadata> {
const config = await getSiteConfig();
return {
title: "Nos Réalisations | Chantiers OBC Maçonnerie Nord",
description:
"Découvrez les réalisations d'OBC Maçonnerie : constructions de maisons, rénovations, assainissement et créations d'accès dans le Nord (59). Galerie photos.",
alternates: { canonical: "https://obc-maconnerie.fr/realisations" },
alternates: { canonical: `${config.url}/realisations` },
};
const realisations = [
{
categorie: "Construction neuve",
titre: "Maison individuelle à Orchies",
desc: "Construction d'une maison de 130 m² — fondations, gros œuvre, dalle béton et ossature.",
zone: "Orchies (59)",
color: "bg-navy",
},
{
categorie: "Rénovation",
titre: "Rénovation complète à Douai",
desc: "Restructuration intérieure complète d'une maison de ville : abattage de cloisons, création d'un escalier neuf, doublages.",
zone: "Douai (59)",
color: "bg-stone",
},
{
categorie: "Assainissement",
titre: "Mise aux normes à Saint-Amand",
desc: "Remplacement d'une fosse septique vétuste par une micro-station d'épuration conforme aux normes.",
zone: "Saint-Amand-les-Eaux (59)",
color: "bg-navy-light",
},
{
categorie: "Création d'accès",
titre: "Entrée en béton imprimé à Mérignies",
desc: "Création d'une entrée de propriété en béton imprimé effet pavés, avec caniveau de drainage.",
zone: "Mérignies (59)",
color: "bg-orange",
},
{
categorie: "Construction neuve",
titre: "Extension ossature bois à Flines",
desc: "Agrandissement d'une maison existante par extension ossature bois, fondations et dalle.",
zone: "Flines-lès-Raches (59)",
color: "bg-navy",
},
{
categorie: "Démolition",
titre: "Démolition & reconstruction à Valenciennes",
desc: "Démolition d'un bâtiment annexe et curage d'une grange pour préparer une rénovation complète.",
zone: "Valenciennes (59)",
color: "bg-stone",
},
];
}
const cats = ["Tous", "Construction neuve", "Rénovation", "Assainissement", "Création d'accès", "Démolition"];
export default function RealisationsPage() {
export default async function RealisationsPage() {
const [realisations, config] = await Promise.all([getRealisations(), getSiteConfig()]);
const { phone, phoneRaw } = config;
return (
<main id="main-content" className="min-h-screen">
<Navbar />
@@ -100,7 +62,7 @@ export default function RealisationsPage() {
<div className="max-w-6xl mx-auto px-4 sm:px-6">
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
{realisations.map((r, i) => (
<ScrollReveal key={r.titre} direction="up" delay={i * 80}>
<ScrollReveal key={r.title} direction="up" delay={i * 80}>
<div className="bg-bg-white border border-border rounded-2xl overflow-hidden hover:shadow-lg transition-all group card-hover">
<div className={`${r.color} h-48 flex items-center justify-center relative`}>
<span className="text-white/10 text-8xl font-black">{i + 1}</span>
@@ -112,12 +74,12 @@ export default function RealisationsPage() {
</div>
<div className="p-5">
<h3 className="text-navy font-bold text-base mb-2 group-hover:text-orange transition-colors">
{r.titre}
{r.title}
</h3>
<p className="text-text-light text-sm leading-relaxed mb-3">{r.desc}</p>
<p className="text-text-light text-sm leading-relaxed mb-3">{r.description}</p>
<div className="flex items-center gap-1 text-text-muted text-xs">
<span>📍</span>
<span>{r.zone}</span>
<span>{r.ville}</span>
</div>
</div>
</div>
@@ -141,10 +103,10 @@ export default function RealisationsPage() {
Demander un devis gratuit
</Link>
<a
href="tel:0674453089"
href={`tel:${phoneRaw}`}
className="inline-flex items-center justify-center gap-2 border-2 border-navy text-navy hover:bg-navy hover:text-white font-bold px-7 py-3.5 rounded-xl transition-colors"
>
06 74 45 30 89
{phone}
</a>
</div>
</div>

View File

@@ -6,7 +6,7 @@ export const metadata: Metadata = {
description:
"Rénovation de maison et appartement à Douai. OBC Maçonnerie, maçon expert en rénovation dans le Nord (59). Devis gratuit.",
keywords: ["rénovation maison Douai", "maçon rénovation Douai", "rénovation appartement Douai", "travaux rénovation Douai"],
alternates: { canonical: "https://obc-maconnerie.fr/renovation-maison-douai" },
alternates: { canonical: "https://obc-terrassement.fr/renovation-maison-douai" },
};
export default function RenovationMaisonDouaiPage() {

View File

@@ -6,7 +6,7 @@ export const metadata: Metadata = {
description:
"Rénovation de maison et appartement à Orchies. OBC Maçonnerie, maçon expert en rénovation dans le Nord (59). Devis gratuit.",
keywords: ["rénovation maison Orchies", "maçon rénovation Orchies", "rénovation appartement Orchies"],
alternates: { canonical: "https://obc-maconnerie.fr/renovation-maison-orchies" },
alternates: { canonical: "https://obc-terrassement.fr/renovation-maison-orchies" },
};
export default function RenovationMaisonOrchiesPage() {

View File

@@ -4,8 +4,12 @@ import Navbar from "@/components/marketing/Navbar";
import Footer from "@/components/marketing/Footer";
import ScrollReveal from "@/components/animations/ScrollReveal";
import ContactForm from "@/components/marketing/ContactForm";
import { getSiteConfig } from "@/lib/content";
export async function generateMetadata(): Promise<Metadata> {
const config = await getSiteConfig();
return {
export const metadata: Metadata = {
title: "Rénovation Maison & Appartement Nord 59 | OBC Maçonnerie",
description:
"Rénovation complète ou partielle de maison et appartement dans le Nord. Benoît Colin vous conseille et adapte chaque projet. Devis gratuit.",
@@ -17,8 +21,9 @@ export const metadata: Metadata = {
"rénovation maison Orchies",
"travaux rénovation Nord",
],
alternates: { canonical: "https://obc-maconnerie.fr/renovation" },
alternates: { canonical: `${config.url}/renovation` },
};
}
const typesTravaux = [
{ icon: "🏚️", title: "Rénovation complète", desc: "Restructuration totale d'une maison ancienne, de la démolition des cloisons existantes à la pose des revêtements." },
@@ -29,7 +34,9 @@ const typesTravaux = [
{ icon: "🏠", title: "Rénovation appartement", desc: "Transformation d'appartements : redistribution des pièces, mise aux normes, travaux de second œuvre." },
];
export default function RenovationPage() {
export default async function RenovationPage() {
const config = await getSiteConfig();
const { phone, phoneRaw } = config;
return (
<main id="main-content" className="min-h-screen">
<Navbar />
@@ -55,9 +62,7 @@ export default function RenovationPage() {
<Link href="/contact" className="inline-flex items-center justify-center gap-2 bg-orange hover:bg-orange-hover text-white font-bold px-7 py-3.5 rounded-xl transition-colors pulse-glow">
Demander un devis gratuit
</Link>
<a href="tel:0674453089" className="inline-flex items-center justify-center gap-2 bg-white/10 hover:bg-white/20 text-white font-semibold px-7 py-3.5 rounded-xl transition-colors border border-white/20">
06 74 45 30 89
</a>
<a href={`tel:${phoneRaw}`} className="inline-flex items-center justify-center gap-2 bg-white/10 hover:bg-white/20 text-white font-semibold px-7 py-3.5 rounded-xl transition-colors border border-white/20">{phone}</a>
</div>
</ScrollReveal>
</div>

View File

@@ -1,6 +1,7 @@
import type { MetadataRoute } from "next";
import { siteConfig } from "@/lib/site-config";
const BASE_URL = process.env.NEXT_PUBLIC_APP_URL || "https://obc-maconnerie.fr";
const BASE_URL = process.env.NEXT_PUBLIC_APP_URL || siteConfig.url;
export default function robots(): MetadataRoute.Robots {
return {

View File

@@ -3,65 +3,23 @@ import Link from "next/link";
import Navbar from "@/components/marketing/Navbar";
import Footer from "@/components/marketing/Footer";
import ScrollReveal from "@/components/animations/ScrollReveal";
import { getServices, getSiteConfig } from "@/lib/content";
export const metadata: Metadata = {
title: "Nos Services | Construction, Rénovation, Assainissement",
description:
"Tous les services d'OBC Maçonnerie : construction de maison, rénovation, assainissement, création d'accès et démolition dans le Nord (59). Devis gratuit.",
alternates: { canonical: "https://obc-maconnerie.fr/services" },
alternates: { canonical: "https://obc-terrassement.fr/services" },
};
const services = [
{
icon: "🏠",
title: "Construction de maison",
desc: "De la conception au gros œuvre, Benoît Colin vous accompagne dans la construction de votre maison individuelle. Fondations, ossature bois, dalles, murs porteurs — tout est pris en charge avec rigueur et savoir-faire.",
href: "/construction-maison",
points: ["Maison individuelle", "Ossature bois", "Fondations", "Gros œuvre complet"],
},
{
icon: "🔨",
title: "Rénovation",
desc: "Que ce soit une rénovation partielle ou complète, OBC Maçonnerie s'adapte à votre projet. Maison ancienne, appartement, restructuration intérieure — chaque chantier est unique et traité comme tel.",
href: "/renovation",
points: ["Rénovation complète", "Restructuration intérieure", "Maison de ville", "Extension"],
},
{
icon: "💧",
title: "Assainissement",
desc: "Mise aux normes de votre système d'assainissement, création d'un nouveau dispositif ou réhabilitation de l'existant. OBC Maçonnerie réalise vos travaux d'assainissement dans les règles de l'art.",
href: "/assainissement",
points: ["Assainissement individuel", "Mise aux normes", "Fosse septique", "Épandage"],
},
{
icon: "🚧",
title: "Création d'accès",
desc: "Voiries, entrées de propriété, chemins, allées — OBC Maçonnerie crée vos accès selon vos besoins et vos envies. Béton, béton imprimé, pavés ou grave compactée.",
href: "/creation-acces",
points: ["Voiries privées", "Entrées de propriété", "Chemins ruraux", "Béton imprimé"],
},
{
icon: "🏗️",
title: "Démolition",
desc: "Démolition totale ou partielle de bâtiment, destruction de murs porteurs, dépose de chapes — OBC Maçonnerie intervient avec tout le matériel et les garanties de sécurité nécessaires.",
href: "/demolition",
points: ["Démolition totale", "Démolition partielle", "Murs porteurs", "Évacuation des gravats"],
},
{
icon: "🤝",
title: "Conseil & Accompagnement",
desc: "Benoît vous guide à chaque étape de votre projet : choix des matériaux, adaptation de plans, coordination des artisans partenaires. Un seul interlocuteur pour un projet serein.",
href: "/contact",
points: ["Conseils matériaux", "Adaptation de plans", "Coordination artisans", "Suivi de chantier"],
},
];
export default async function ServicesPage() {
const [services, config] = await Promise.all([getServices(), getSiteConfig()]);
const { phone, phoneRaw } = config;
export default function ServicesPage() {
return (
<main id="main-content" className="min-h-screen">
<Navbar />
{/* Hero */}
<section className="bg-navy py-16 md:py-20">
<div className="max-w-4xl mx-auto px-4 sm:px-6 text-center">
<ScrollReveal direction="up">
@@ -74,25 +32,26 @@ export default function ServicesPage() {
</div>
</section>
{/* Services */}
<section className="py-16 md:py-20 bg-bg">
<div className="max-w-5xl mx-auto px-4 sm:px-6 space-y-8">
{services.map((s, i) => (
<ScrollReveal key={s.title} direction="up" delay={i * 60}>
{services.map((s, i) => {
const href = s.slug === "conseil" ? "/contact" : `/${s.slug}`;
return (
<ScrollReveal key={s.slug} direction="up" delay={i * 60}>
<div className="bg-bg-white border border-border rounded-2xl p-6 md:p-8 flex flex-col md:flex-row gap-6">
<div className="text-5xl shrink-0">{s.icon}</div>
<div className="flex-1">
<h2 className="text-xl font-bold text-navy mb-2">{s.title}</h2>
<p className="text-text-light text-sm leading-relaxed mb-4">{s.desc}</p>
<p className="text-text-light text-sm leading-relaxed mb-4">{s.longDescription}</p>
<div className="flex flex-wrap gap-2 mb-5">
{s.points.map((p) => (
<span key={p} className="bg-bg-muted text-text-light text-xs font-medium px-3 py-1 rounded-full">
{p}
{s.keywords.map((k) => (
<span key={k} className="bg-bg-muted text-text-light text-xs font-medium px-3 py-1 rounded-full">
{k}
</span>
))}
</div>
<Link
href={s.href}
href={href}
className="inline-flex items-center gap-1.5 text-orange font-semibold text-sm hover:underline"
>
En savoir plus
@@ -103,32 +62,24 @@ export default function ServicesPage() {
</div>
</div>
</ScrollReveal>
))}
);
})}
</div>
</section>
{/* CTA */}
<section className="py-16 bg-stone-bg">
<div className="max-w-2xl mx-auto px-4 text-center">
<ScrollReveal direction="up">
<h2 className="text-2xl md:text-3xl font-bold text-navy mb-4">
Vous avez un projet ? Parlons-en.
</h2>
<h2 className="text-2xl md:text-3xl font-bold text-navy mb-4">Vous avez un projet ? Parlons-en.</h2>
<p className="text-text-light mb-6">
Benoît se déplace gratuitement pour évaluer votre projet et vous remettre un devis détaillé.
</p>
<div className="flex flex-col sm:flex-row gap-4 justify-center">
<Link
href="/contact"
className="inline-flex items-center justify-center gap-2 bg-orange hover:bg-orange-hover text-white font-bold px-7 py-3.5 rounded-xl transition-colors"
>
<Link href="/contact" className="inline-flex items-center justify-center gap-2 bg-orange hover:bg-orange-hover text-white font-bold px-7 py-3.5 rounded-xl transition-colors">
Demander un devis gratuit
</Link>
<a
href="tel:0674453089"
className="inline-flex items-center justify-center gap-2 border-2 border-navy text-navy hover:bg-navy hover:text-white font-bold px-7 py-3.5 rounded-xl transition-colors"
>
06 74 45 30 89
<a href={`tel:${phoneRaw}`} className="inline-flex items-center justify-center gap-2 border-2 border-navy text-navy hover:bg-navy hover:text-white font-bold px-7 py-3.5 rounded-xl transition-colors">
{phone}
</a>
</div>
</ScrollReveal>

View File

@@ -1,6 +1,7 @@
import type { MetadataRoute } from "next";
import { siteConfig } from "@/lib/site-config";
const BASE_URL = process.env.NEXT_PUBLIC_APP_URL || "https://obc-maconnerie.fr";
const BASE_URL = process.env.NEXT_PUBLIC_APP_URL || siteConfig.url;
export default function sitemap(): MetadataRoute.Sitemap {
const now = new Date();

View File

@@ -1,6 +1,19 @@
import Link from "next/link";
import { siteConfig } from "@/lib/site-config";
export default function Footer() {
const {
name,
dirigeant,
phone,
phoneRaw,
address,
siren,
footerServicesNav,
footerMainNav,
footerLegalNav,
} = siteConfig;
return (
<footer className="bg-navy text-white pt-12 pb-6">
<div className="max-w-6xl mx-auto px-4 sm:px-6 lg:px-8">
@@ -17,35 +30,33 @@ export default function Footer() {
</div>
</div>
<p className="text-white/70 text-sm leading-relaxed mb-4 max-w-xs">
Benoît Colin, maçon expert en construction de maison, rénovation et gros œuvre dans le Nord. De la première pierre à la remise des clés.
{dirigeant}, maçon expert en construction de maison, rénovation et gros
œuvre dans le Nord. De la première pierre à la remise des clés.
</p>
<a
href="tel:0674453089"
href={`tel:${phoneRaw}`}
className="inline-flex items-center gap-2 text-orange-light font-bold text-base hover:text-white 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 74 45 30 89
{phone}
</a>
<p className="text-white/40 text-xs mt-2">
221 Route de Saint-Amand, 59310 Mouchin
</p>
<p className="text-white/40 text-xs mt-2">{address}</p>
</div>
{/* Services */}
<div>
<h4 className="text-white font-semibold text-sm mb-4 uppercase tracking-wide">Services</h4>
<h4 className="text-white font-semibold text-sm mb-4 uppercase tracking-wide">
Services
</h4>
<ul className="space-y-2">
{[
{ href: "/construction-maison", label: "Construction de maison" },
{ href: "/renovation", label: "Rénovation" },
{ href: "/assainissement", label: "Assainissement" },
{ href: "/creation-acces", label: "Création d'accès" },
{ href: "/demolition", label: "Démolition" },
].map((item) => (
{footerServicesNav.map((item) => (
<li key={item.href}>
<Link href={item.href} className="text-white/60 hover:text-white text-sm transition-colors">
<Link
href={item.href}
className="text-white/60 hover:text-white text-sm transition-colors"
>
{item.label}
</Link>
</li>
@@ -53,33 +64,33 @@ export default function Footer() {
</ul>
</div>
{/* Navigation */}
{/* Navigation + Légal */}
<div>
<h4 className="text-white font-semibold text-sm mb-4 uppercase tracking-wide">Navigation</h4>
<h4 className="text-white font-semibold text-sm mb-4 uppercase tracking-wide">
Navigation
</h4>
<ul className="space-y-2">
{[
{ href: "/", label: "Accueil" },
{ href: "/realisations", label: "Réalisations" },
{ href: "/partenaires", label: "Partenaires" },
{ href: "/contact", label: "Contact" },
{ href: "/blog", label: "Blog" },
].map((item) => (
{footerMainNav.map((item) => (
<li key={item.href}>
<Link href={item.href} className="text-white/60 hover:text-white text-sm transition-colors">
<Link
href={item.href}
className="text-white/60 hover:text-white text-sm transition-colors"
>
{item.label}
</Link>
</li>
))}
</ul>
<h4 className="text-white font-semibold text-sm mb-3 mt-5 uppercase tracking-wide">Légal</h4>
<h4 className="text-white font-semibold text-sm mb-3 mt-5 uppercase tracking-wide">
Légal
</h4>
<ul className="space-y-2">
{[
{ href: "/mentions-legales", label: "Mentions légales" },
{ href: "/confidentialite", label: "Confidentialité" },
{ href: "/cgv", label: "CGV" },
].map((item) => (
{footerLegalNav.map((item) => (
<li key={item.href}>
<Link href={item.href} className="text-white/60 hover:text-white text-sm transition-colors">
<Link
href={item.href}
className="text-white/60 hover:text-white text-sm transition-colors"
>
{item.label}
</Link>
</li>
@@ -91,10 +102,12 @@ export default function Footer() {
{/* Bottom */}
<div className="pt-6 flex flex-col md:flex-row items-center justify-between gap-3">
<p className="text-white/40 text-xs text-center md:text-left">
&copy; {new Date().getFullYear()} OBC Maçonnerie &mdash; Benoît Colin &middot; SIREN 531 827 871
&copy; {new Date().getFullYear()} {name} &mdash; {dirigeant} &middot; SIREN{" "}
{siren.replace(/(\d{3})(\d{3})(\d{3})/, "$1 $2 $3")}
</p>
<p className="text-white/40 text-xs text-center md:text-right">
Orchies &middot; Mouchin &middot; Douai &middot; Valenciennes &middot; Saint-Amand-les-Eaux &mdash;{" "}
Orchies &middot; Mouchin &middot; Douai &middot; Valenciennes &middot;
Saint-Amand-les-Eaux &mdash;{" "}
<span className="text-white/30">Site réalisé par HookLab</span>
</p>
</div>

View File

@@ -3,6 +3,7 @@ import Navbar from "@/components/marketing/Navbar";
import Footer from "@/components/marketing/Footer";
import ScrollReveal from "@/components/animations/ScrollReveal";
import ContactForm from "@/components/marketing/ContactForm";
import { siteConfig } from "@/lib/site-config";
interface LocalSEOPageProps {
ville: string;
@@ -14,13 +15,13 @@ interface LocalSEOPageProps {
distanceMouchin?: string;
}
const services = [
{ icon: "🏠", label: "Construction de maison", href: "/construction-maison" },
{ icon: "🔨", label: "Rénovation", href: "/renovation" },
{ icon: "💧", label: "Assainissement", href: "/assainissement" },
{ icon: "🚧", label: "Création d'accès", href: "/creation-acces" },
{ icon: "🏗️", label: "Démolition", href: "/demolition" },
];
// Services dérivés de siteConfig (sans "conseil" qui redirige vers /contact)
const services = siteConfig.footerServicesNav.map((s) => {
const found = siteConfig.services.find(
(sc) => sc.title === s.label || `/${sc.slug}` === s.href
);
return { icon: found?.icon ?? "🔧", label: s.label, href: s.href };
});
export default function LocalSEOPage({
ville,
@@ -31,6 +32,8 @@ export default function LocalSEOPage({
texteLocal,
distanceMouchin,
}: LocalSEOPageProps) {
const { phone, phoneRaw, address } = siteConfig;
return (
<main id="main-content" className="min-h-screen">
<Navbar />
@@ -57,8 +60,8 @@ export default function LocalSEOPage({
<Link href="/contact" className="inline-flex items-center justify-center gap-2 bg-orange hover:bg-orange-hover text-white font-bold px-7 py-3.5 rounded-xl transition-colors pulse-glow">
Demander un devis gratuit
</Link>
<a href="tel:0674453089" className="inline-flex items-center justify-center gap-2 bg-white/10 hover:bg-white/20 text-white font-semibold px-7 py-3.5 rounded-xl transition-colors border border-white/20">
06 74 45 30 89
<a href={`tel:${phoneRaw}`} className="inline-flex items-center justify-center gap-2 bg-white/10 hover:bg-white/20 text-white font-semibold px-7 py-3.5 rounded-xl transition-colors border border-white/20">
{phone}
</a>
</div>
</ScrollReveal>
@@ -116,9 +119,9 @@ export default function LocalSEOPage({
</div>
<div>
<p className="text-navy font-bold text-sm">Benoît Colin OBC Maçonnerie</p>
<p className="text-text-muted text-xs">221 Route de Saint-Amand, 59310 Mouchin</p>
<a href="tel:0674453089" className="text-orange font-bold text-sm hover:underline">
06 74 45 30 89
<p className="text-text-muted text-xs">{address}</p>
<a href={`tel:${phoneRaw}`} className="text-orange font-bold text-sm hover:underline">
{phone}
</a>
</div>
</div>

View File

@@ -2,16 +2,11 @@
import { useState } from "react";
import Link from "next/link";
const navLinks = [
{ href: "/services", label: "Nos services" },
{ href: "/realisations", label: "Réalisations" },
{ href: "/partenaires", label: "Partenaires" },
{ href: "/contact", label: "Contact" },
];
import { siteConfig } from "@/lib/site-config";
export default function Navbar() {
const [open, setOpen] = useState(false);
const { name, phone, phoneRaw, nav } = siteConfig;
return (
<nav
@@ -22,9 +17,9 @@ export default function Navbar() {
<div className="max-w-6xl mx-auto px-4 sm:px-6 lg:px-8">
<div className="flex items-center justify-between h-16">
{/* Logo */}
<Link href="/" className="flex items-center gap-2.5" aria-label="OBC Maçonnerie - Accueil">
<Link href="/" className="flex items-center gap-2.5" aria-label={`${name} - Accueil`}>
<div className="w-9 h-9 bg-navy rounded-lg flex items-center justify-center shrink-0">
<span className="text-white font-bold text-sm">OBC</span>
<span className="text-white font-bold text-xs">OBC</span>
</div>
<div className="flex flex-col leading-tight">
<span className="text-navy font-bold text-sm leading-none">OBC</span>
@@ -34,7 +29,7 @@ export default function Navbar() {
{/* Desktop links */}
<div className="hidden md:flex items-center gap-6">
{navLinks.map((link) => (
{nav.map((link) => (
<Link
key={link.href}
href={link.href}
@@ -48,13 +43,13 @@ export default function Navbar() {
{/* CTA desktop */}
<div className="hidden md:block">
<a
href="tel:0674453089"
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-hover transition-colors pulse-glow"
href={`tel:${phoneRaw}`}
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-hover 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 74 45 30 89
{phone}
</a>
</div>
@@ -80,7 +75,7 @@ export default function Navbar() {
{/* Mobile menu */}
{open && (
<div className="md:hidden border-t border-border py-4 space-y-1">
{navLinks.map((link) => (
{nav.map((link) => (
<Link
key={link.href}
href={link.href}
@@ -92,14 +87,14 @@ export default function Navbar() {
))}
<div className="pt-2">
<a
href="tel:0674453089"
href={`tel:${phoneRaw}`}
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>
Appeler Benoît 06 74 45 30 89
{phone}
</a>
</div>
</div>

85
lib/content.ts Normal file
View File

@@ -0,0 +1,85 @@
// lib/content.ts
// Couche d'abstraction entre les données et les composants.
//
// AUJOURD'HUI : lit siteConfig (données statiques en JSON)
// DEMAIN : remplacer chaque return par un appel Payload CMS
// Les composants n'ont JAMAIS à changer.
//
// Exemple de migration future :
// - return siteConfig.services
// + return await payload.find({ collection: 'services' }).then(r => r.docs)
import { siteConfig } from "./site-config";
import type {
Service,
Realisation,
Testimonial,
FAQItem,
BlogPost,
Partner,
NavItem,
} from "@/types/content";
// ── Navigation ────────────────────────────────────────────────
export async function getNavItems(): Promise<NavItem[]> {
// FUTURE: return await payload.findGlobal({ slug: 'navigation' })
return [...siteConfig.nav];
}
// ── Config globale ────────────────────────────────────────────
export async function getSiteConfig() {
// FUTURE: return await payload.findGlobal({ slug: 'site-settings' })
return siteConfig;
}
// ── Services ──────────────────────────────────────────────────
export async function getServices(): Promise<Service[]> {
// FUTURE: return await payload.find({ collection: 'services', sort: 'order' }).then(r => r.docs)
return [...siteConfig.services];
}
export async function getServiceBySlug(slug: string): Promise<Service | null> {
// FUTURE: return await payload.find({ collection: 'services', where: { slug: { equals: slug } } }).then(r => r.docs[0] ?? null)
return siteConfig.services.find((s) => s.slug === slug) ?? null;
}
// ── Réalisations ──────────────────────────────────────────────
export async function getRealisations(): Promise<Realisation[]> {
// FUTURE: return await payload.find({ collection: 'realisations', sort: '-publishedAt' }).then(r => r.docs)
return [...siteConfig.realisations];
}
// ── Témoignages ───────────────────────────────────────────────
export async function getTestimonials(): Promise<Testimonial[]> {
// FUTURE: return await payload.find({ collection: 'testimonials', where: { featured: { equals: true } } }).then(r => r.docs)
return [...siteConfig.testimonials];
}
// ── FAQ ───────────────────────────────────────────────────────
export async function getFAQ(): Promise<FAQItem[]> {
// FUTURE: return await payload.find({ collection: 'faq', sort: 'order' }).then(r => r.docs)
return [...siteConfig.faq];
}
// ── Partenaires ───────────────────────────────────────────────
export async function getPartners(): Promise<Partner[]> {
// FUTURE: return await payload.find({ collection: 'partners', sort: 'order' }).then(r => r.docs)
return [...siteConfig.partners];
}
// ── Blog ──────────────────────────────────────────────────────
export async function getBlogPosts(): Promise<BlogPost[]> {
// FUTURE: return await payload.find({ collection: 'articles', where: { status: { equals: 'published' } }, sort: '-publishedAt' }).then(r => r.docs)
return [...siteConfig.blogPosts];
}
export async function getBlogPost(slug: string): Promise<BlogPost | null> {
// FUTURE: return await payload.find({ collection: 'articles', where: { slug: { equals: slug } } }).then(r => r.docs[0] ?? null)
return siteConfig.blogPosts.find((p) => p.slug === slug) ?? null;
}
// ── Valeurs / Piliers ─────────────────────────────────────────
export async function getValues() {
// FUTURE: return await payload.find({ collection: 'values', sort: 'order' }).then(r => r.docs)
return [...siteConfig.values];
}

380
lib/site-config.ts Normal file
View File

@@ -0,0 +1,380 @@
// lib/site-config.ts
// Source unique de vérité pour toutes les données du site OBC Maçonnerie.
// Toute modification de contenu (textes, services, FAQ...) se fait ICI.
// Les composants consomment ces données via lib/content.ts — jamais en dur.
export const siteConfig = {
name: "OBC Maçonnerie",
dirigeant: "Benoît Colin",
phone: "06 74 45 30 89",
phoneRaw: "0674453089",
email: "contact@obc-terrassement.fr",
address: "221 Route de Saint-Amand, 59310 Mouchin",
addressLine1: "221 Route de Saint-Amand",
addressLocality: "Mouchin",
addressPostalCode: "59310",
addressRegion: "Hauts-de-France",
addressCountry: "FR",
siren: "531827871",
url: "https://obc-terrassement.fr",
zones: [
"Orchies",
"Mouchin",
"Flines-lès-Raches",
"Château-l'Abbaye",
"Mérignies",
"Douai",
"Valenciennes",
"Saint-Amand-les-Eaux",
],
zoneDescription: "20 à 30 km autour de Mouchin (Nord 59)",
nav: [
{ label: "Accueil", href: "/" },
{ label: "Services", href: "/services" },
{ label: "Réalisations", href: "/realisations" },
{ label: "Blog", href: "/blog" },
{ label: "Contact", href: "/contact" },
],
footerServicesNav: [
{ label: "Construction de maison", href: "/construction-maison" },
{ label: "Rénovation", href: "/renovation" },
{ label: "Assainissement", href: "/assainissement" },
{ label: "Création d'accès", href: "/creation-acces" },
{ label: "Démolition", href: "/demolition" },
],
footerMainNav: [
{ label: "Accueil", href: "/" },
{ label: "Réalisations", href: "/realisations" },
{ label: "Partenaires", href: "/partenaires" },
{ label: "Contact", href: "/contact" },
{ label: "Blog", href: "/blog" },
],
footerLegalNav: [
{ label: "Mentions légales", href: "/mentions-legales" },
{ label: "Confidentialité", href: "/confidentialite" },
{ label: "CGV", href: "/cgv" },
],
seo: {
title: "OBC Maçonnerie | Constructeur & Maçon à Orchies (Nord 59)",
description:
"Benoît Colin, maçon expert à Mouchin. Construction de maison, rénovation, assainissement et gros œuvre dans un rayon de 30km autour d'Orchies. Devis gratuit.",
},
hero: {
title: "Maçon & Constructeur dans le Nord",
subtitle:
"Construction de maison, rénovation, assainissement et gros œuvre — expertise autour d'Orchies",
cta: "Demander un devis gratuit",
ctaSecondary: "Voir nos réalisations",
badge:
"Disponible, à l'écoute, Benoît vous accompagne de la première pierre à la remise des clés",
stats: [
{ val: "15+", label: "ans d'expérience" },
{ val: "200+", label: "chantiers réalisés" },
{ val: "30km", label: "de rayon d'action" },
],
},
services: [
{
slug: "construction-maison",
title: "Construction de maison",
shortDescription:
"Fondations, ossature bois, gros œuvre — on bâtit votre projet de A à Z avec vous.",
longDescription:
"De la conception des fondations à la pose du toit, Benoît vous accompagne à chaque étape de votre construction. Maison individuelle, ossature bois, béton banché — chaque projet est unique.",
icon: "🏠",
keywords: [
"construction maison Nord",
"maçon construction maison Orchies",
"fondation ossature bois Nord",
],
},
{
slug: "renovation",
title: "Rénovation",
shortDescription:
"Maison ou appartement, on s'adapte à votre projet et vos envies.",
longDescription:
"Rénovation partielle ou complète, intérieure et extérieure. Benoît adapte chaque projet à votre budget et vos envies. Restructuration, création d'ouvertures, extension.",
icon: "🔨",
keywords: [
"rénovation maison Nord 59",
"maçon rénovation Douai",
"maçon rénovation Valenciennes",
],
},
{
slug: "assainissement",
title: "Assainissement",
shortDescription:
"Mise aux normes et création de systèmes d'assainissement fiables.",
longDescription:
"Installation et mise aux normes de vos systèmes d'assainissement individuel et collectif. Fosse toutes eaux, micro-station, épandage — dans les règles de l'art.",
icon: "💧",
keywords: [
"assainissement maison Nord",
"assainissement individuel Nord 59",
],
},
{
slug: "creation-acces",
title: "Création d'accès",
shortDescription: "Voiries, entrées, chemins — on crée vos accès sur mesure.",
longDescription:
"Création de voiries, entrées de propriété et chemins d'accès. Béton, béton imprimé, pavés, gravier stabilisé — travail soigné et durable.",
icon: "🚧",
keywords: [
"création accès maison Nord",
"voirie entrée propriété Nord 59",
],
},
{
slug: "demolition",
title: "Démolition",
shortDescription:
"Démolition totale ou partielle, avec toutes les garanties de sécurité.",
longDescription:
"Démolition de bâtiments, murs et ouvrages en toute sécurité. Évacuation des gravats incluse. Préparation du terrain pour votre future construction.",
icon: "🏗️",
keywords: [
"démolition maison Nord 59",
"démolition bâtiment Nord",
],
},
{
slug: "conseil",
title: "Conseil & Accompagnement",
shortDescription:
"Benoît vous éclaire dans vos choix : matériaux, plans, adaptations — on réfléchit ensemble.",
longDescription:
"Un seul interlocuteur pour tout votre projet. Benoît analyse votre plan, vous conseille sur les matériaux et coordonne les artisans partenaires.",
icon: "🤝",
keywords: [
"entrepreneur maçon Nord 59",
"gros œuvre Nord",
],
},
],
values: [
{
title: "Proche de vous",
description:
"Disponible, à l'écoute. Benoît se déplace sur votre chantier pour comprendre votre projet et vous proposer les meilleures solutions.",
icon: "📍",
},
{
title: "Conseil expert",
description:
"Il vous guide dans vos choix de matériaux, adapte les plans d'architecte, suggère des améliorations auxquelles vous n'avez pas pensé.",
icon: "💡",
},
{
title: "Acteur de confiance",
description:
"Transparent à chaque étape, il vous rassure et vous explique chaque décision. Pas de surprise, pas de mauvaise nouvelle.",
icon: "🛡️",
},
{
title: "Passionné du métier",
description:
"On ne fait jamais deux fois la même maison. Benoît réfléchit avec vous pour que le résultat vous ressemble.",
icon: "❤️",
},
],
partners: [
{ label: "Électricité", icon: "⚡", desc: "Installation électrique aux normes NF C 15-100, tableau de distribution, prises, éclairage." },
{ label: "Plomberie", icon: "🔧", desc: "Plomberie sanitaire, chauffage central, installation de salles de bains et cuisines." },
{ label: "Charpente", icon: "🪵", desc: "Charpente traditionnelle ou industrielle, structure bois pour combles aménageables ou non." },
{ label: "Couverture", icon: "🏚️", desc: "Pose de toiture, tuiles, ardoises, zinc — étanchéité et finitions soignées." },
{ label: "Isolation", icon: "🧱", desc: "Isolation thermique et phonique par l'intérieur ou l'extérieur, combles, planchers." },
{ label: "Menuiserie", icon: "🚪", desc: "Fenêtres, portes, vérandas, volets — menuiserie bois, PVC ou aluminium." },
{ label: "Carrelage", icon: "🔳", desc: "Pose de carrelage, parquet, faïence — pour sols et murs, intérieur et extérieur." },
{ label: "Peinture", icon: "🎨", desc: "Peinture intérieure et extérieure, enduits décoratifs, ravalement de façade." },
],
partnersTitle: "Seul on va vite, ensemble on va plus loin.",
partnersMessage:
"Grâce à notre réseau de partenaires de confiance, nous coordonnons l'ensemble des corps de métier pour que votre maison prenne forme de A à Z.",
faq: [
{
question: "Dans quelle zone intervenez-vous ?",
answer:
"Nous intervenons dans un rayon de 20 à 30 km autour de Mouchin (59310) : Orchies, Flines-lès-Raches, Château-l'Abbaye, Mérignies, Douai, Valenciennes, Saint-Amand-les-Eaux et les communes alentour.",
},
{
question: "Faites-vous des devis gratuits ?",
answer:
"Oui, le devis est gratuit et sans engagement. Benoît se déplace sur votre chantier pour évaluer votre projet et vous remettre une estimation détaillée.",
},
{
question: "Pouvez-vous adapter un plan d'architecte ?",
answer:
"Absolument. C'est même l'une de nos spécialités. Benoît analyse votre plan et vous suggère des adaptations pour optimiser l'espace, le rendu final et votre budget.",
},
{
question: "Combien de temps dure une construction de maison ?",
answer:
"En moyenne, comptez 10 à 18 mois pour une construction neuve selon la complexité du projet et les délais de livraison des matériaux. Benoît vous donnera un calendrier précis lors du devis.",
},
{
question: "Travaillez-vous avec d'autres artisans ?",
answer:
"Oui. Nous coordonnons un réseau de partenaires de confiance (électriciens, plombiers, charpentiers, couvreurs, menuisiers, carreleurs, peintres) pour vous livrer une maison complète avec un seul interlocuteur.",
},
],
testimonials: [
{
name: "Christophe & Marie L.",
ville: "Orchies",
service: "construction-maison",
text: "Benoît nous a accompagnés de A à Z dans la construction de notre maison. Il a su adapter le plan d'architecte à nos envies tout en respectant notre budget. Disponible, professionnel, et vraiment à l'écoute. On recommande les yeux fermés.",
rating: 5,
},
{
name: "Sophie D.",
ville: "Douai",
service: "renovation",
text: "On lui a confié la rénovation complète de notre maison de 1970. Benoît a pris le temps de tout nous expliquer, a proposé des solutions auxquelles on n'avait pas pensé, et le résultat est magnifique. Un vrai professionnel.",
rating: 5,
},
{
name: "Famille Moreau",
ville: "Saint-Amand-les-Eaux",
service: "assainissement",
text: "Mise aux normes de notre système d'assainissement réalisée dans les délais et en toute transparence. Benoît nous a expliqué chaque étape. Très sérieux et propre dans son travail.",
rating: 5,
},
],
realisations: [
{
title: "Maison individuelle à Orchies",
ville: "Orchies (59)",
service: "construction-maison",
categorie: "Construction neuve",
description:
"Construction d'une maison de 130 m² — fondations, gros œuvre, dalle béton et ossature.",
color: "bg-navy",
image: "/images/realisations/chantier-1.jpg",
},
{
title: "Rénovation complète à Douai",
ville: "Douai (59)",
service: "renovation",
categorie: "Rénovation",
description:
"Restructuration intérieure complète d'une maison de ville : abattage de cloisons, création d'un escalier neuf, doublages.",
color: "bg-stone",
image: "/images/realisations/chantier-2.jpg",
},
{
title: "Mise aux normes à Saint-Amand",
ville: "Saint-Amand-les-Eaux (59)",
service: "assainissement",
categorie: "Assainissement",
description:
"Remplacement d'une fosse septique vétuste par une micro-station d'épuration conforme aux normes.",
color: "bg-navy-light",
image: "/images/realisations/chantier-3.jpg",
},
{
title: "Entrée en béton imprimé à Mérignies",
ville: "Mérignies (59)",
service: "creation-acces",
categorie: "Création d'accès",
description:
"Création d'une entrée de propriété en béton imprimé effet pavés, avec caniveau de drainage.",
color: "bg-orange",
image: "/images/realisations/chantier-4.jpg",
},
{
title: "Extension ossature bois à Flines",
ville: "Flines-lès-Raches (59)",
service: "construction-maison",
categorie: "Construction neuve",
description:
"Agrandissement d'une maison existante par extension ossature bois, fondations et dalle.",
color: "bg-navy",
image: "/images/realisations/chantier-5.jpg",
},
{
title: "Démolition & reconstruction à Valenciennes",
ville: "Valenciennes (59)",
service: "demolition",
categorie: "Démolition",
description:
"Démolition d'un bâtiment annexe et curage d'une grange pour préparer une rénovation complète.",
color: "bg-stone",
image: "/images/realisations/chantier-6.jpg",
},
],
blogPosts: [
{
slug: "combien-coute-construction-maison-nord",
titre: "Combien coûte la construction d'une maison dans le Nord en 2025 ?",
extrait:
"Budget, matériaux, terrain, main-d'œuvre — tout ce qu'il faut savoir pour estimer le coût de votre construction neuve dans le Nord.",
cat: "Construction",
date: "15 février 2025",
readTime: "6 min",
},
{
slug: "etapes-renovation-maison-ancienne",
titre: "Les étapes clés d'une rénovation de maison ancienne",
extrait:
"Vous avez acheté une maison ancienne dans le Nord et vous voulez la rénover ? Voici les étapes indispensables pour réussir votre projet.",
cat: "Rénovation",
date: "8 janvier 2025",
readTime: "5 min",
},
{
slug: "assainissement-non-collectif-obligations",
titre: "Assainissement non collectif : vos obligations légales",
extrait:
"Contrôle SPANC, mise aux normes, vente immobilière — tout ce que vous devez savoir sur l'assainissement non collectif.",
cat: "Assainissement",
date: "20 décembre 2024",
readTime: "4 min",
},
{
slug: "ossature-bois-avantages",
titre: "Ossature bois : pourquoi choisir ce mode constructif ?",
extrait:
"Légèreté, performance thermique, rapidité de construction — l'ossature bois a de nombreux avantages. OBC Maçonnerie vous explique.",
cat: "Construction",
date: "5 novembre 2024",
readTime: "5 min",
},
{
slug: "travaux-renovation-sans-permis-construction",
titre: "Quels travaux de rénovation ne nécessitent pas de permis ?",
extrait:
"Permis de construire, déclaration préalable, simple déclaration — on vous explique les règles selon la nature de vos travaux.",
cat: "Rénovation",
date: "18 octobre 2024",
readTime: "4 min",
},
{
slug: "fondations-maison-quels-types",
titre: "Les différents types de fondations pour une maison",
extrait:
"Semelles filantes, radier, pieux — quelles fondations choisir selon votre terrain et votre projet de construction ?",
cat: "Construction",
date: "2 septembre 2024",
readTime: "5 min",
},
],
} as const;
export type SiteConfig = typeof siteConfig;

54
payload/README.md Normal file
View File

@@ -0,0 +1,54 @@
# Payload CMS — Préparation
Ce dossier contient les schémas Payload CMS commentés, prêts à être activés
quand le projet bascule de contenu statique vers un CMS administrable.
## Architecture cible
```
payload/
├── collections/
│ ├── Articles.ts → Articles de blog
│ ├── Realisations.ts → Galerie chantiers
│ ├── Services.ts → Services proposés
│ ├── Testimonials.ts → Avis clients
│ └── FAQ.ts → Questions fréquentes
└── globals/
└── SiteSettings.ts → Paramètres globaux du site
```
## Migration (3 étapes)
### Étape 1 — Installer Payload CMS
```bash
npm install payload @payloadcms/db-postgres @payloadcms/richtext-lexical
```
### Étape 2 — Activer les collections
Décommenter le code dans chaque fichier `collections/*.ts` et `globals/*.ts`,
puis créer `payload.config.ts` à la racine :
```ts
import { buildConfig } from 'payload'
import { Services } from './payload/collections/Services'
import { Realisations } from './payload/collections/Realisations'
import { Articles } from './payload/collections/Articles'
import { Testimonials } from './payload/collections/Testimonials'
import { FAQ } from './payload/collections/FAQ'
import { SiteSettings } from './payload/globals/SiteSettings'
export default buildConfig({
collections: [Services, Realisations, Articles, Testimonials, FAQ],
globals: [SiteSettings],
// ...db, admin, etc.
})
```
### Étape 3 — Mettre à jour lib/content.ts
Remplacer les `return siteConfig.xxx` par les appels Payload commentés.
**Les composants n'ont pas à changer.**
## Données actuelles
Toutes les données sont dans `lib/site-config.ts`.
Les composants les consomment via `lib/content.ts`.

View File

@@ -0,0 +1,94 @@
// payload/collections/Articles.ts
// Schéma Payload CMS pour les articles de blog.
// COMMENTÉ — activé lors de la migration vers Payload.
/*
import type { CollectionConfig } from 'payload'
import { lexicalEditor } from '@payloadcms/richtext-lexical'
export const Articles: CollectionConfig = {
slug: 'articles',
admin: {
useAsTitle: 'title',
defaultColumns: ['title', 'category', 'status', 'publishedAt'],
},
fields: [
{
name: 'title',
type: 'text',
required: true,
label: 'Titre de l\'article',
},
{
name: 'slug',
type: 'text',
required: true,
unique: true,
label: 'URL (slug)',
admin: {
description: 'ex: combien-coute-construction-maison-nord',
},
},
{
name: 'excerpt',
type: 'textarea',
label: 'Extrait (meta description)',
},
{
name: 'content',
type: 'richText',
editor: lexicalEditor(),
label: 'Contenu complet',
},
{
name: 'category',
type: 'select',
options: [
{ label: 'Construction', value: 'construction' },
{ label: 'Rénovation', value: 'renovation' },
{ label: 'Assainissement', value: 'assainissement' },
{ label: 'Conseils', value: 'conseils' },
],
label: 'Catégorie',
},
{
name: 'publishedAt',
type: 'date',
label: 'Date de publication',
},
{
name: 'status',
type: 'select',
options: [
{ label: 'Brouillon', value: 'draft' },
{ label: 'Publié', value: 'published' },
],
defaultValue: 'draft',
label: 'Statut',
},
{
name: 'seoTitle',
type: 'text',
label: 'Titre SEO (optionnel — remplace title)',
},
{
name: 'seoDescription',
type: 'textarea',
label: 'Description SEO (optionnel — remplace excerpt)',
},
],
}
*/
export type PayloadArticle = {
id: string;
slug: string;
title: string;
excerpt: string;
content: unknown; // Lexical rich text
category: string;
publishedAt: string;
status: "draft" | "published";
seoTitle?: string;
seoDescription?: string;
};

View File

@@ -0,0 +1,42 @@
// payload/collections/FAQ.ts
// Schéma Payload CMS pour la FAQ.
// COMMENTÉ — activé lors de la migration vers Payload.
/*
import type { CollectionConfig } from 'payload'
export const FAQ: CollectionConfig = {
slug: 'faq',
admin: {
useAsTitle: 'question',
defaultColumns: ['question', 'order'],
},
fields: [
{
name: 'question',
type: 'text',
required: true,
label: 'Question',
},
{
name: 'answer',
type: 'textarea',
required: true,
label: 'Réponse',
},
{
name: 'order',
type: 'number',
label: 'Ordre d\'affichage',
defaultValue: 0,
},
],
}
*/
export type PayloadFAQItem = {
id: string;
question: string;
answer: string;
order: number;
};

View File

@@ -0,0 +1,84 @@
// payload/collections/Realisations.ts
// Schéma Payload CMS pour les réalisations / portfolio.
// COMMENTÉ — activé lors de la migration vers Payload.
/*
import type { CollectionConfig } from 'payload'
export const Realisations: CollectionConfig = {
slug: 'realisations',
admin: {
useAsTitle: 'title',
defaultColumns: ['title', 'ville', 'service', 'publishedAt'],
},
fields: [
{
name: 'title',
type: 'text',
required: true,
label: 'Titre du chantier',
},
{
name: 'ville',
type: 'text',
required: true,
label: 'Ville',
},
{
name: 'service',
type: 'relationship',
relationTo: 'services',
label: 'Service associé',
},
{
name: 'description',
type: 'textarea',
label: 'Description courte',
},
{
name: 'image',
type: 'upload',
relationTo: 'media',
label: 'Photo principale',
},
{
name: 'gallery',
type: 'array',
label: 'Galerie photos',
fields: [
{
name: 'image',
type: 'upload',
relationTo: 'media',
},
{
name: 'caption',
type: 'text',
},
],
},
{
name: 'featured',
type: 'checkbox',
label: 'Mettre en avant (page accueil)',
defaultValue: false,
},
{
name: 'publishedAt',
type: 'date',
label: 'Date du chantier',
},
],
}
*/
export type PayloadRealisation = {
id: string;
title: string;
ville: string;
service: string;
description: string;
image: string;
featured: boolean;
publishedAt: string;
};

View File

@@ -0,0 +1,78 @@
// payload/collections/Services.ts
// Schéma Payload CMS pour les services OBC Maçonnerie.
// COMMENTÉ — activé lors de la migration vers Payload.
//
// Pour activer : décommenter et importer dans payload.config.ts
/*
import type { CollectionConfig } from 'payload'
export const Services: CollectionConfig = {
slug: 'services',
admin: {
useAsTitle: 'title',
defaultColumns: ['title', 'slug', 'updatedAt'],
},
fields: [
{
name: 'slug',
type: 'text',
required: true,
unique: true,
admin: { description: 'Identifiant URL (ex: construction-maison)' },
},
{
name: 'title',
type: 'text',
required: true,
label: 'Titre du service',
},
{
name: 'shortDescription',
type: 'text',
required: true,
label: 'Description courte (carte home page)',
},
{
name: 'longDescription',
type: 'textarea',
label: 'Description longue (page dédiée)',
},
{
name: 'icon',
type: 'text',
label: 'Emoji icône',
admin: { description: 'ex: 🏠' },
},
{
name: 'keywords',
type: 'array',
label: 'Mots-clés SEO',
fields: [
{
name: 'keyword',
type: 'text',
},
],
},
{
name: 'order',
type: 'number',
label: 'Ordre d\'affichage',
defaultValue: 0,
},
],
}
*/
// Type exporté pour l'autocomplétion — reste actif même sans Payload
export type PayloadService = {
id: string;
slug: string;
title: string;
shortDescription: string;
longDescription: string;
icon: string;
keywords: { keyword: string }[];
order: number;
};

View File

@@ -0,0 +1,64 @@
// payload/collections/Testimonials.ts
// Schéma Payload CMS pour les témoignages clients.
// COMMENTÉ — activé lors de la migration vers Payload.
/*
import type { CollectionConfig } from 'payload'
export const Testimonials: CollectionConfig = {
slug: 'testimonials',
admin: {
useAsTitle: 'name',
defaultColumns: ['name', 'ville', 'service', 'rating', 'featured'],
},
fields: [
{
name: 'name',
type: 'text',
required: true,
label: 'Nom du client',
},
{
name: 'ville',
type: 'text',
label: 'Ville',
},
{
name: 'service',
type: 'relationship',
relationTo: 'services',
label: 'Service concerné',
},
{
name: 'text',
type: 'textarea',
required: true,
label: 'Témoignage',
},
{
name: 'rating',
type: 'number',
min: 1,
max: 5,
defaultValue: 5,
label: 'Note (1 à 5)',
},
{
name: 'featured',
type: 'checkbox',
label: 'Afficher sur la page d\'accueil',
defaultValue: true,
},
],
}
*/
export type PayloadTestimonial = {
id: string;
name: string;
ville: string;
service: string;
text: string;
rating: number;
featured: boolean;
};

View File

@@ -0,0 +1,95 @@
// payload/globals/SiteSettings.ts
// Schéma Payload CMS pour les paramètres globaux du site.
// COMMENTÉ — activé lors de la migration vers Payload.
//
// Permet à Benoît (ou à un admin) de modifier les infos
// de contact, le texte du hero, etc. sans toucher au code.
/*
import type { GlobalConfig } from 'payload'
export const SiteSettings: GlobalConfig = {
slug: 'site-settings',
admin: {
group: 'Paramètres',
},
fields: [
// ── Informations de contact ───────────────────────────────
{
name: 'contact',
type: 'group',
label: 'Contact',
fields: [
{ name: 'phone', type: 'text', label: 'Téléphone' },
{ name: 'email', type: 'email', label: 'Email' },
{ name: 'address', type: 'text', label: 'Adresse complète' },
],
},
// ── Hero page d'accueil ───────────────────────────────────
{
name: 'hero',
type: 'group',
label: 'Section Hero (page d\'accueil)',
fields: [
{ name: 'title', type: 'text', label: 'Titre H1' },
{ name: 'subtitle', type: 'textarea', label: 'Sous-titre' },
{ name: 'badge', type: 'text', label: 'Badge/accroche' },
{ name: 'cta', type: 'text', label: 'CTA principal' },
{ name: 'ctaSecondary', type: 'text', label: 'CTA secondaire' },
],
},
// ── Zone d'intervention ────────────────────────────────────
{
name: 'zones',
type: 'array',
label: 'Villes d\'intervention',
fields: [
{ name: 'city', type: 'text', label: 'Ville' },
],
},
{
name: 'zoneDescription',
type: 'text',
label: 'Description zone (ex: 20 à 30 km autour de Mouchin)',
},
// ── SEO global ────────────────────────────────────────────
{
name: 'seo',
type: 'group',
label: 'SEO global',
fields: [
{ name: 'title', type: 'text', label: 'Titre SEO par défaut' },
{ name: 'description', type: 'textarea', label: 'Description SEO par défaut' },
],
},
// ── Message partenaires ───────────────────────────────────
{
name: 'partnersMessage',
type: 'textarea',
label: 'Message section partenaires',
},
],
}
*/
export type PayloadSiteSettings = {
contact: {
phone: string;
email: string;
address: string;
};
hero: {
title: string;
subtitle: string;
badge: string;
cta: string;
ctaSecondary: string;
};
zones: { city: string }[];
zoneDescription: string;
seo: {
title: string;
description: string;
};
partnersMessage: string;
};

62
types/content.ts Normal file
View File

@@ -0,0 +1,62 @@
// types/content.ts
// Types partagés entre lib/content.ts et les composants.
// Ces types correspondent exactement aux schémas Payload CMS futurs
// définis dans /payload/collections/*.ts
export type NavItem = {
label: string;
href: string;
};
export type Service = {
slug: string;
title: string;
shortDescription: string;
longDescription: string;
icon: string;
keywords: string[];
};
export type Realisation = {
title: string;
ville: string;
service: string;
categorie: string;
description: string;
color: string;
image: string;
};
export type Testimonial = {
name: string;
ville: string;
service: string;
text: string;
rating: number;
};
export type FAQItem = {
question: string;
answer: string;
};
export type Partner = {
label: string;
icon: string;
desc: string;
};
export type BlogPost = {
slug: string;
titre: string;
extrait: string;
cat: string;
date: string;
readTime: string;
};
export type Value = {
title: string;
description: string;
icon: string;
};