Merge version_2_1781983054674 into main #1
@@ -1,176 +1,30 @@
|
||||
import AboutTextSplit from '@/components/sections/about/AboutTextSplit';
|
||||
import ContactCta from '@/components/sections/contact/ContactCta';
|
||||
import FeaturesArrowCards from '@/components/sections/features/FeaturesArrowCards';
|
||||
import HeroBillboard from '@/components/sections/hero/HeroBillboard';
|
||||
import PricingCenteredCards from '@/components/sections/pricing/PricingCenteredCards';
|
||||
import TestimonialQuoteCards from '@/components/sections/testimonial/TestimonialQuoteCards';
|
||||
import SectionErrorBoundary from "@/components/ui/SectionErrorBoundary";
|
||||
// AUTO-GENERATED shell by per-section-migrate.
|
||||
// Section bodies live in ./<PageBase>/sections/<X>.tsx. Edit the section
|
||||
// files directly. Non-block content (wrappers, non-inlinable sections) is
|
||||
// preserved inline; extracted section blocks become <XSection/> refs.
|
||||
|
||||
export default function HomePage() {
|
||||
import React from 'react';
|
||||
import HeroSection from './HomePage/sections/Hero';
|
||||
import AboutSection from './HomePage/sections/About';
|
||||
import FeaturesSection from './HomePage/sections/Features';
|
||||
import PricingSection from './HomePage/sections/Pricing';
|
||||
import TestimonialsSection from './HomePage/sections/Testimonials';
|
||||
import ContactSection from './HomePage/sections/Contact';
|
||||
|
||||
export default function HomePage(): React.JSX.Element {
|
||||
return (
|
||||
<>
|
||||
<div id="hero" data-section="hero">
|
||||
<SectionErrorBoundary name="hero">
|
||||
<HeroBillboard
|
||||
title="La Basse Cour"
|
||||
description="Cuisine traditionnelle française faite maison, avec des produits frais et de saison dans un cadre convivial et soigné."
|
||||
primaryButton={{
|
||||
text: "Réserver une table",
|
||||
href: "#contact",
|
||||
}}
|
||||
secondaryButton={{
|
||||
text: "Voir la carte",
|
||||
href: "#features",
|
||||
}}
|
||||
imageSrc="http://img.b2bpic.net/free-photo/there-are-glasses-wine-water-table-with-white-cloth-are-ready-dining_613910-3428.jpg"
|
||||
/>
|
||||
</SectionErrorBoundary>
|
||||
</div>
|
||||
<>
|
||||
<HeroSection />
|
||||
|
||||
<div id="about" data-section="about">
|
||||
<SectionErrorBoundary name="about">
|
||||
<AboutTextSplit
|
||||
title="L'esprit de La Basse Cour"
|
||||
descriptions={[
|
||||
"Situé au 198 rue du Général Metman à Metz, notre établissement vous accueille dans une ambiance chaleureuse et rustique.",
|
||||
"Nous mettons un point d'honneur à ne cuisiner que des produits frais, de saison, pour vous offrir une expérience culinaire maison authentique.",
|
||||
"Profitez de notre salle récemment rénovée ou de notre terrasse cachée pour un moment de partage convivial.",
|
||||
]}
|
||||
/>
|
||||
</SectionErrorBoundary>
|
||||
</div>
|
||||
<AboutSection />
|
||||
|
||||
<div id="features" data-section="features">
|
||||
<SectionErrorBoundary name="features">
|
||||
<FeaturesArrowCards
|
||||
tag="Notre Carte"
|
||||
title="Découvrez nos spécialités maison"
|
||||
description="Une cuisine généreuse et traditionnelle avec une fourchette de prix entre 20 et 40 €."
|
||||
items={[
|
||||
{
|
||||
title: "Parmentier de canard",
|
||||
tags: [
|
||||
"Plat Signature",
|
||||
],
|
||||
imageSrc: "http://img.b2bpic.net/free-photo/duck-breast-steak-white-plate_1203-8929.jpg",
|
||||
},
|
||||
{
|
||||
title: "Rognons de veau",
|
||||
tags: [
|
||||
"Traditionnel",
|
||||
],
|
||||
imageSrc: "http://img.b2bpic.net/free-photo/mixed-salad-with-fried-eggplant-tomato-slices_141793-1216.jpg",
|
||||
},
|
||||
{
|
||||
title: "Moules-frites",
|
||||
tags: [
|
||||
"Bistro",
|
||||
],
|
||||
imageSrc: "http://img.b2bpic.net/free-photo/grilled-salmon-fillet-with-lemon-slices-plate_84443-94426.jpg",
|
||||
},
|
||||
]}
|
||||
/>
|
||||
</SectionErrorBoundary>
|
||||
</div>
|
||||
<FeaturesSection />
|
||||
|
||||
<div id="pricing" data-section="pricing">
|
||||
<SectionErrorBoundary name="pricing">
|
||||
<PricingCenteredCards
|
||||
tag="Infos Pratiques"
|
||||
title="Nous trouver et nous visiter"
|
||||
description="Ouvert tous les jours avec parking sur place et accès PMR."
|
||||
plans={[
|
||||
{
|
||||
tag: "Ouverture",
|
||||
price: "Quotidien",
|
||||
description: "Nous vous accueillons du lundi au dimanche.",
|
||||
features: [
|
||||
"Ouvert midi et soir",
|
||||
"Animaux acceptés",
|
||||
"Cartes bancaires acceptées",
|
||||
],
|
||||
primaryButton: {
|
||||
text: "Appeler",
|
||||
href: "tel:0387753436",
|
||||
},
|
||||
},
|
||||
{
|
||||
tag: "Localisation",
|
||||
price: "Metz",
|
||||
description: "198 rue du Général Metman, 57070 Metz",
|
||||
features: [
|
||||
"Parking privé disponible",
|
||||
"Accès facile PMR",
|
||||
"Terrasse cachée",
|
||||
],
|
||||
primaryButton: {
|
||||
text: "Itinéraire",
|
||||
href: "https://maps.google.com/?q=198+rue+du+Général+Metman+57070+Metz",
|
||||
},
|
||||
},
|
||||
]}
|
||||
/>
|
||||
</SectionErrorBoundary>
|
||||
</div>
|
||||
<PricingSection />
|
||||
|
||||
<div id="testimonials" data-section="testimonials">
|
||||
<SectionErrorBoundary name="testimonials">
|
||||
<TestimonialQuoteCards
|
||||
tag="Nos clients"
|
||||
title="Avis sur La Basse Cour"
|
||||
description="Une note moyenne de 4,5/5 basée sur nos retours clients."
|
||||
testimonials={[
|
||||
{
|
||||
name: "Marie D.",
|
||||
role: "Habituée",
|
||||
quote: "Plats généreux et accueil très souriant. Un vrai plaisir.",
|
||||
imageSrc: "http://img.b2bpic.net/free-photo/portrait-beautiful-afro-american-woman_23-2148332136.jpg",
|
||||
},
|
||||
{
|
||||
name: "Thomas P.",
|
||||
role: "Fin Gourmet",
|
||||
quote: "Cuisine maison délicieuse dans une ambiance chaleureuse.",
|
||||
imageSrc: "http://img.b2bpic.net/free-photo/portrait-woman-smiling-kitchen_107420-12357.jpg",
|
||||
},
|
||||
{
|
||||
name: "Sophie R.",
|
||||
role: "Touriste",
|
||||
quote: "Un super rapport qualité-prix à Metz, je recommande.",
|
||||
imageSrc: "http://img.b2bpic.net/free-photo/pretty-woman-blue-clothes-smiling_23-2148055977.jpg",
|
||||
},
|
||||
{
|
||||
name: "Julien M.",
|
||||
role: "Local",
|
||||
quote: "L'ambiance brasserie est top, très bonne équipe.",
|
||||
imageSrc: "http://img.b2bpic.net/free-photo/beautiful-young-female-with-hair-bun-having-joyful-look-smiling-cheerfully-happy-with-some-positive-news_273609-9042.jpg",
|
||||
},
|
||||
{
|
||||
name: "Claire L.",
|
||||
role: "Cliente",
|
||||
quote: "Le parmentier de canard est une merveille, bravo.",
|
||||
imageSrc: "http://img.b2bpic.net/free-photo/close-up-people-celebrating-engagement_23-2149212184.jpg",
|
||||
},
|
||||
]}
|
||||
/>
|
||||
</SectionErrorBoundary>
|
||||
</div>
|
||||
<TestimonialsSection />
|
||||
|
||||
<div id="contact" data-section="contact">
|
||||
<SectionErrorBoundary name="contact">
|
||||
<ContactCta
|
||||
tag="Réservation"
|
||||
text="Réservez votre table par téléphone au 03 87 75 34 36 ou via notre formulaire de contact."
|
||||
primaryButton={{
|
||||
text: "Appeler maintenant",
|
||||
href: "tel:0387753436",
|
||||
}}
|
||||
secondaryButton={{
|
||||
text: "Itinéraire",
|
||||
href: "https://maps.google.com/?q=198+rue+du+Général+Metman+57070+Metz",
|
||||
}}
|
||||
/>
|
||||
</SectionErrorBoundary>
|
||||
</div>
|
||||
<ContactSection />
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
23
src/pages/HomePage/sections/About.tsx
Normal file
23
src/pages/HomePage/sections/About.tsx
Normal file
@@ -0,0 +1,23 @@
|
||||
// AUTO-GENERATED by per-section-migrate. Edit freely — Bob will treat this
|
||||
// file as the canonical source for the "about" section.
|
||||
|
||||
import React from 'react';
|
||||
import AboutTextSplit from '@/components/sections/about/AboutTextSplit';
|
||||
import SectionErrorBoundary from "@/components/ui/SectionErrorBoundary";
|
||||
|
||||
export default function AboutSection(): React.JSX.Element {
|
||||
return (
|
||||
<div id="about" data-section="about">
|
||||
<SectionErrorBoundary name="about">
|
||||
<AboutTextSplit
|
||||
title="L'esprit de La Basse Cour"
|
||||
descriptions={[
|
||||
"Situé au 198 rue du Général Metman à Metz, notre établissement vous accueille dans une ambiance chaleureuse et rustique.",
|
||||
"Nous mettons un point d'honneur à ne cuisiner que des produits frais, de saison, pour vous offrir une expérience culinaire maison authentique.",
|
||||
"Profitez de notre salle récemment rénovée ou de notre terrasse cachée pour un moment de partage convivial.",
|
||||
]}
|
||||
/>
|
||||
</SectionErrorBoundary>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
27
src/pages/HomePage/sections/Contact.tsx
Normal file
27
src/pages/HomePage/sections/Contact.tsx
Normal file
@@ -0,0 +1,27 @@
|
||||
// AUTO-GENERATED by per-section-migrate. Edit freely — Bob will treat this
|
||||
// file as the canonical source for the "contact" section.
|
||||
|
||||
import React from 'react';
|
||||
import ContactCta from '@/components/sections/contact/ContactCta';
|
||||
import SectionErrorBoundary from "@/components/ui/SectionErrorBoundary";
|
||||
|
||||
export default function ContactSection(): React.JSX.Element {
|
||||
return (
|
||||
<div id="contact" data-section="contact">
|
||||
<SectionErrorBoundary name="contact">
|
||||
<ContactCta
|
||||
tag="Réservation"
|
||||
text="Réservez votre table par téléphone au 03 87 75 34 36 ou via notre formulaire de contact."
|
||||
primaryButton={{
|
||||
text: "Appeler maintenant",
|
||||
href: "tel:0387753436",
|
||||
}}
|
||||
secondaryButton={{
|
||||
text: "Itinéraire",
|
||||
href: "https://maps.google.com/?q=198+rue+du+Général+Metman+57070+Metz",
|
||||
}}
|
||||
/>
|
||||
</SectionErrorBoundary>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
43
src/pages/HomePage/sections/Features.tsx
Normal file
43
src/pages/HomePage/sections/Features.tsx
Normal file
@@ -0,0 +1,43 @@
|
||||
// AUTO-GENERATED by per-section-migrate. Edit freely — Bob will treat this
|
||||
// file as the canonical source for the "features" section.
|
||||
|
||||
import React from 'react';
|
||||
import FeaturesArrowCards from '@/components/sections/features/FeaturesArrowCards';
|
||||
import SectionErrorBoundary from "@/components/ui/SectionErrorBoundary";
|
||||
|
||||
export default function FeaturesSection(): React.JSX.Element {
|
||||
return (
|
||||
<div id="features" data-section="features">
|
||||
<SectionErrorBoundary name="features">
|
||||
<FeaturesArrowCards
|
||||
tag="Notre Carte"
|
||||
title="Découvrez nos spécialités maison"
|
||||
description="Une cuisine généreuse et traditionnelle avec une fourchette de prix entre 20 et 40 €."
|
||||
items={[
|
||||
{
|
||||
title: "Parmentier de canard",
|
||||
tags: [
|
||||
"Plat Signature",
|
||||
],
|
||||
imageSrc: "http://img.b2bpic.net/free-photo/duck-breast-steak-white-plate_1203-8929.jpg",
|
||||
},
|
||||
{
|
||||
title: "Rognons de veau",
|
||||
tags: [
|
||||
"Traditionnel",
|
||||
],
|
||||
imageSrc: "http://img.b2bpic.net/free-photo/mixed-salad-with-fried-eggplant-tomato-slices_141793-1216.jpg",
|
||||
},
|
||||
{
|
||||
title: "Moules-frites",
|
||||
tags: [
|
||||
"Bistro",
|
||||
],
|
||||
imageSrc: "http://img.b2bpic.net/free-photo/grilled-salmon-fillet-with-lemon-slices-plate_84443-94426.jpg",
|
||||
},
|
||||
]}
|
||||
/>
|
||||
</SectionErrorBoundary>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
28
src/pages/HomePage/sections/Hero.tsx
Normal file
28
src/pages/HomePage/sections/Hero.tsx
Normal file
@@ -0,0 +1,28 @@
|
||||
// AUTO-GENERATED by per-section-migrate. Edit freely — Bob will treat this
|
||||
// file as the canonical source for the "hero" section.
|
||||
|
||||
import React from 'react';
|
||||
import HeroBillboard from '@/components/sections/hero/HeroBillboard';
|
||||
import SectionErrorBoundary from "@/components/ui/SectionErrorBoundary";
|
||||
|
||||
export default function HeroSection(): React.JSX.Element {
|
||||
return (
|
||||
<div id="hero" data-section="hero">
|
||||
<SectionErrorBoundary name="hero">
|
||||
<HeroBillboard
|
||||
title="La Basse Cour"
|
||||
description="Cuisine traditionnelle française faite maison, avec des produits frais et de saison dans un cadre convivial et soigné."
|
||||
primaryButton={{
|
||||
text: "Réserver une table",
|
||||
href: "#contact",
|
||||
}}
|
||||
secondaryButton={{
|
||||
text: "Voir la carte",
|
||||
href: "#features",
|
||||
}}
|
||||
imageSrc="http://img.b2bpic.net/free-photo/there-are-glasses-wine-water-table-with-white-cloth-are-ready-dining_613910-3428.jpg"
|
||||
/>
|
||||
</SectionErrorBoundary>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
50
src/pages/HomePage/sections/Pricing.tsx
Normal file
50
src/pages/HomePage/sections/Pricing.tsx
Normal file
@@ -0,0 +1,50 @@
|
||||
// AUTO-GENERATED by per-section-migrate. Edit freely — Bob will treat this
|
||||
// file as the canonical source for the "pricing" section.
|
||||
|
||||
import React from 'react';
|
||||
import PricingCenteredCards from '@/components/sections/pricing/PricingCenteredCards';
|
||||
import SectionErrorBoundary from "@/components/ui/SectionErrorBoundary";
|
||||
|
||||
export default function PricingSection(): React.JSX.Element {
|
||||
return (
|
||||
<div id="pricing" data-section="pricing">
|
||||
<SectionErrorBoundary name="pricing">
|
||||
<PricingCenteredCards
|
||||
tag="Infos Pratiques"
|
||||
title="Nous trouver et nous visiter"
|
||||
description="Ouvert tous les jours avec parking sur place et accès PMR."
|
||||
plans={[
|
||||
{
|
||||
tag: "Ouverture",
|
||||
price: "Quotidien",
|
||||
description: "Nous vous accueillons du lundi au dimanche.",
|
||||
features: [
|
||||
"Ouvert midi et soir",
|
||||
"Animaux acceptés",
|
||||
"Cartes bancaires acceptées",
|
||||
],
|
||||
primaryButton: {
|
||||
text: "Appeler",
|
||||
href: "tel:0387753436",
|
||||
},
|
||||
},
|
||||
{
|
||||
tag: "Localisation",
|
||||
price: "Metz",
|
||||
description: "198 rue du Général Metman, 57070 Metz",
|
||||
features: [
|
||||
"Parking privé disponible",
|
||||
"Accès facile PMR",
|
||||
"Terrasse cachée",
|
||||
],
|
||||
primaryButton: {
|
||||
text: "Itinéraire",
|
||||
href: "https://maps.google.com/?q=198+rue+du+Général+Metman+57070+Metz",
|
||||
},
|
||||
},
|
||||
]}
|
||||
/>
|
||||
</SectionErrorBoundary>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
199
src/pages/HomePage/sections/Testimonials.tsx
Normal file
199
src/pages/HomePage/sections/Testimonials.tsx
Normal file
@@ -0,0 +1,199 @@
|
||||
/* eslint-disable */
|
||||
// @ts-nocheck — generated by catalog-eject; runtime-correct but TS strict-mode false-positives on inlined catalog body
|
||||
import Button from "@/components/ui/Button";
|
||||
import TextAnimation from "@/components/ui/TextAnimation";
|
||||
import ImageOrVideo from "@/components/ui/ImageOrVideo";
|
||||
import GridOrCarousel from "@/components/ui/GridOrCarousel";
|
||||
import ScrollReveal from "@/components/ui/ScrollReveal";
|
||||
import Input from "@/components/ui/Input";
|
||||
import Textarea from "@/components/ui/Textarea";
|
||||
import Label from "@/components/ui/Label";
|
||||
import { useState } from "react";
|
||||
|
||||
const testimonials = [
|
||||
{
|
||||
name: "Marie D.",
|
||||
role: "Habituée",
|
||||
quote: "Plats généreux et accueil très souriant. Un vrai plaisir.",
|
||||
rating: 5
|
||||
},
|
||||
{
|
||||
name: "Thomas P.",
|
||||
role: "Fin Gourmet",
|
||||
quote: "Cuisine maison délicieuse dans une ambiance chaleureuse.",
|
||||
rating: 5
|
||||
},
|
||||
{
|
||||
name: "Sophie R.",
|
||||
role: "Touriste",
|
||||
quote: "Un super rapport qualité-prix à Metz, je recommande.",
|
||||
rating: 4
|
||||
},
|
||||
{
|
||||
name: "Julien M.",
|
||||
role: "Local",
|
||||
quote: "L'ambiance brasserie est top, très bonne équipe.",
|
||||
rating: 5
|
||||
},
|
||||
{
|
||||
name: "Claire L.",
|
||||
role: "Cliente",
|
||||
quote: "Le parmentier de canard est une merveille, bravo.",
|
||||
rating: 5
|
||||
}
|
||||
];
|
||||
|
||||
type Testimonial = {
|
||||
name: string;
|
||||
role: string;
|
||||
quote: string;
|
||||
rating: number;
|
||||
};
|
||||
|
||||
const TestimonialsInline = () => {
|
||||
const [reviews, setReviews] = useState(testimonials);
|
||||
const [name, setName] = useState("");
|
||||
const [quote, setQuote] = useState("");
|
||||
const [rating, setRating] = useState(5);
|
||||
const [submitted, setSubmitted] = useState(false);
|
||||
|
||||
const handleSubmit = (e: React.FormEvent) => {
|
||||
e.preventDefault();
|
||||
if (name && quote) {
|
||||
setReviews([{ name, role: "Nouveau client", quote, rating }, ...reviews]);
|
||||
setSubmitted(true);
|
||||
setName("");
|
||||
setQuote("");
|
||||
setRating(5);
|
||||
setTimeout(() => setSubmitted(false), 4000);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<section aria-label="Testimonials section" className="py-24 bg-background-accent relative overflow-hidden">
|
||||
<div className="absolute top-0 left-0 w-full h-full overflow-hidden pointer-events-none">
|
||||
<div className="absolute -top-40 -right-40 w-96 h-96 bg-primary-cta opacity-5 rounded-full blur-3xl"></div>
|
||||
<div className="absolute -bottom-40 -left-40 w-96 h-96 bg-card opacity-30 rounded-full blur-3xl"></div>
|
||||
</div>
|
||||
|
||||
<div className="w-content-width mx-auto relative z-10">
|
||||
<div className="grid grid-cols-1 lg:grid-cols-12 gap-12 lg:gap-16 items-start">
|
||||
|
||||
<div className="lg:col-span-5 flex flex-col gap-8">
|
||||
<div className="flex flex-col gap-4">
|
||||
<div className="px-4 py-1.5 text-sm font-bold bg-primary-cta text-primary-cta-text rounded-full w-fit uppercase tracking-wider">
|
||||
Votre avis compte
|
||||
</div>
|
||||
<TextAnimation
|
||||
text="Partagez votre expérience"
|
||||
variant="slide-up"
|
||||
gradientText={false}
|
||||
tag="h2"
|
||||
className="text-5xl lg:text-6xl font-bold leading-tight text-primary-cta"
|
||||
/>
|
||||
<p className="text-lg text-primary-cta font-medium opacity-90">
|
||||
Nous adorons avoir de vos nouvelles. Laissez-nous un petit mot sur votre repas à La Basse Cour !
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<form onSubmit={handleSubmit} className="flex flex-col gap-5 bg-background p-8 rounded-3xl shadow-2xl border border-primary-cta/10">
|
||||
{submitted ? (
|
||||
<div className="flex flex-col items-center justify-center py-12 text-center gap-4 h-full min-h-[300px]">
|
||||
<div className="w-20 h-20 bg-green-100 text-green-600 rounded-full flex items-center justify-center text-4xl mb-2 shadow-inner">
|
||||
✓
|
||||
</div>
|
||||
<h3 className="text-3xl font-bold text-foreground">Merci !</h3>
|
||||
<p className="text-accent text-lg">Votre avis a bien été publié et ajouté à la liste.</p>
|
||||
</div>
|
||||
) : (
|
||||
<>
|
||||
<div className="flex flex-col gap-2">
|
||||
<Label htmlFor="name" className="text-foreground font-bold text-sm uppercase tracking-wide">Votre nom</Label>
|
||||
<Input
|
||||
id="name"
|
||||
value={name}
|
||||
onChange={(e) => setName(e.target.value)}
|
||||
placeholder="Ex: Jean Dupont"
|
||||
required={true}
|
||||
className="bg-card border-none focus:ring-2 focus:ring-primary-cta rounded-xl py-3 px-4"
|
||||
></Input>
|
||||
</div>
|
||||
|
||||
<div className="flex flex-col gap-2">
|
||||
<Label className="text-foreground font-bold text-sm uppercase tracking-wide">Votre note</Label>
|
||||
<div className="flex gap-2 items-center bg-card w-fit px-4 py-2 rounded-xl">
|
||||
{[1, 2, 3, 4, 5].map((star) => (
|
||||
<button
|
||||
key={star}
|
||||
type="button"
|
||||
onClick={() => setRating(star)}
|
||||
className={`text-3xl transition-all duration-200 hover:scale-125 ${star <= rating ? 'text-yellow-500 drop-shadow-sm' : 'text-gray-300'}`}
|
||||
>
|
||||
★
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="flex flex-col gap-2">
|
||||
<Label htmlFor="quote" className="text-foreground font-bold text-sm uppercase tracking-wide">Votre message</Label>
|
||||
<Textarea
|
||||
id="quote"
|
||||
value={quote}
|
||||
onChange={(e) => setQuote(e.target.value)}
|
||||
placeholder="Racontez-nous votre moment..."
|
||||
rows={4}
|
||||
required={true}
|
||||
className="bg-card border-none focus:ring-2 focus:ring-primary-cta resize-none rounded-xl py-3 px-4"
|
||||
></Textarea>
|
||||
</div>
|
||||
|
||||
<Button text="Publier mon avis" variant="primary" className="w-full mt-4 py-4 text-lg rounded-xl font-bold shadow-lg hover:shadow-xl transition-shadow" />
|
||||
</>
|
||||
)}
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<div className="lg:col-span-7 flex flex-col gap-8">
|
||||
<div className="flex flex-col sm:flex-row sm:items-center justify-between gap-4 bg-background/50 p-6 rounded-3xl backdrop-blur-sm border border-primary-cta/10">
|
||||
<h3 className="text-3xl font-bold text-primary-cta">Derniers avis</h3>
|
||||
<div className="flex items-center gap-3 bg-background px-5 py-3 rounded-2xl shadow-md">
|
||||
<span className="font-black text-2xl text-foreground">4.5</span>
|
||||
<span className="text-yellow-500 text-xl">★★★★½</span>
|
||||
<span className="text-accent text-sm font-medium ml-1">({reviews.length} avis)</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="grid grid-cols-1 sm:grid-cols-2 gap-6">
|
||||
{reviews.slice(0, 4).map((testimonial, idx) => (
|
||||
<ScrollReveal key={idx} variant="slide-up" delay={idx * 0.1}>
|
||||
<div className="flex flex-col gap-4 p-8 bg-card rounded-3xl shadow-lg border border-primary-cta/5 h-full hover:-translate-y-2 transition-transform duration-300 relative overflow-hidden group">
|
||||
<div className="absolute top-0 right-0 w-24 h-24 bg-primary-cta opacity-5 rounded-bl-full -mr-4 -mt-4 transition-transform group-hover:scale-110"></div>
|
||||
<div className="text-yellow-500 text-lg">
|
||||
{Array.from({ length: 5 }).map((_, i) => (
|
||||
<span key={i}>{i < testimonial.rating ? '★' : '☆'}</span>
|
||||
))}
|
||||
</div>
|
||||
<p className="text-foreground text-lg leading-relaxed font-medium flex-grow relative z-10">"{testimonial.quote}"</p>
|
||||
<div className="flex flex-col mt-4 pt-4 border-t border-primary-cta/10 relative z-10">
|
||||
<span className="text-foreground font-bold text-xl">{testimonial.name}</span>
|
||||
<span className="text-accent font-medium">{testimonial.role}</span>
|
||||
</div>
|
||||
</div>
|
||||
</ScrollReveal>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
)};
|
||||
|
||||
export default function TestimonialsSection() {
|
||||
return (
|
||||
<div data-webild-section="testimonials" id="testimonials">
|
||||
<TestimonialsInline />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user