Retour au catalogue
Comparison Cards
Cartes de comparaison cote a cote avec prix, features et badge populaire.
comparisonmedium Both Responsive a11y
minimalboldsaasuniversalgrid
Theme
"use client";
import { motion } from "framer-motion";
import { Check, ArrowRight } from "lucide-react";
interface ComparisonPlan {
name: string;
price: string;
description: string;
features: string[];
highlighted?: boolean;
ctaLabel: string;
}
interface ComparisonCardsProps {
title?: string;
subtitle?: string;
plans?: ComparisonPlan[];
}
const ease: [number, number, number, number] = [0.16, 1, 0.3, 1];
export default function ComparisonCards({
title = "Comparez nos offres",
subtitle = "",
plans = [],
}: ComparisonCardsProps) {
return (
<section className="py-20 lg:py-28 px-6" style={{ background: "var(--color-background)" }}>
<div className="mx-auto max-w-6xl">
<motion.div
initial={{ opacity: 0, y: 16 }}
whileInView={{ opacity: 1, y: 0 }}
transition={{ duration: 0.5, ease }}
viewport={{ once: true }}
className="text-center mb-14"
>
<h2 className="text-3xl md:text-4xl font-bold" style={{ color: "var(--color-foreground)" }}>{title}</h2>
{subtitle && <p className="mt-3 text-base" style={{ color: "var(--color-foreground-muted)" }}>{subtitle}</p>}
</motion.div>
<div className="grid grid-cols-1 md:grid-cols-3 gap-6">
{plans.map((plan, i) => (
<motion.div
key={i}
initial={{ opacity: 0, y: 20 }}
whileInView={{ opacity: 1, y: 0 }}
transition={{ duration: 0.5, ease, delay: i * 0.1 }}
viewport={{ once: true }}
className="relative rounded-2xl p-6 flex flex-col"
style={{
background: plan.highlighted ? "var(--color-accent)" : "var(--color-background-card)",
border: plan.highlighted ? "none" : "1px solid var(--color-border)",
}}
>
{plan.highlighted && (
<span className="absolute -top-3 left-1/2 -translate-x-1/2 px-3 py-1 text-[10px] font-bold uppercase tracking-wider rounded-full" style={{ background: "var(--color-background)", color: "var(--color-accent)" }}>
Populaire
</span>
)}
<h3 className="text-lg font-semibold" style={{ color: plan.highlighted ? "var(--color-background)" : "var(--color-foreground)" }}>{plan.name}</h3>
<div className="mt-2 text-3xl font-bold" style={{ color: plan.highlighted ? "var(--color-background)" : "var(--color-foreground)" }}>{plan.price}</div>
<p className="mt-2 text-sm" style={{ color: plan.highlighted ? "var(--color-background)" : "var(--color-foreground-muted)", opacity: plan.highlighted ? 0.8 : 1 }}>{plan.description}</p>
<ul className="mt-6 flex-1 flex flex-col gap-2.5">
{plan.features.map((f, fi) => (
<li key={fi} className="flex items-center gap-2 text-sm" style={{ color: plan.highlighted ? "var(--color-background)" : "var(--color-foreground-muted)" }}>
<Check size={14} style={{ color: plan.highlighted ? "var(--color-background)" : "var(--color-accent)", flexShrink: 0 }} />
{f}
</li>
))}
</ul>
<motion.button
whileHover={{ scale: 1.02 }}
whileTap={{ scale: 0.98 }}
className="mt-6 flex items-center justify-center gap-2 w-full py-2.5 text-sm font-medium rounded-xl transition-colors"
style={{
background: plan.highlighted ? "var(--color-background)" : "var(--color-accent)",
color: plan.highlighted ? "var(--color-accent)" : "var(--color-background)",
}}
>
{plan.ctaLabel}
<ArrowRight size={14} />
</motion.button>
</motion.div>
))}
</div>
</div>
</section>
);
}