Retour au catalogue
API Integration Cards
Cartes d'integration API avec badge de statut, snippet de code et documentation inline.
integrationscomplex Both Responsive a11y
minimalcorporatesaasagencygrid
Theme
"use client";
import { useRef, useState } from "react";
import { motion, useInView } from "framer-motion";
import { Code2, Copy, Check, ExternalLink, Terminal } from "lucide-react";
interface ApiCard {
name: string;
method: string;
endpoint: string;
description: string;
snippet: string;
status: string;
}
interface IntegrationApiCardsProps {
title?: string;
subtitle?: string;
apis?: ApiCard[];
docsLabel?: string;
docsLink?: string;
}
const EASE: [number, number, number, number] = [0.16, 1, 0.3, 1];
const methodColors: Record<string, string> = {
GET: "var(--color-accent)",
POST: "var(--color-accent)",
PUT: "var(--color-foreground-muted)",
DELETE: "var(--color-foreground-muted)",
};
export default function IntegrationApiCards({
title = "API REST",
subtitle = "Integrez en quelques minutes.",
apis = [],
docsLabel = "Documentation",
docsLink = "#",
}: IntegrationApiCardsProps) {
const ref = useRef<HTMLDivElement>(null);
const inView = useInView(ref, { once: true, margin: "-80px" });
const [copiedIndex, setCopiedIndex] = useState<number | null>(null);
const handleCopy = (snippet: string, index: number) => {
navigator.clipboard.writeText(snippet).catch(() => {});
setCopiedIndex(index);
setTimeout(() => setCopiedIndex(null), 2000);
};
return (
<section
ref={ref}
style={{
padding: "5rem 1.5rem",
background: "var(--color-background)",
}}
>
<div style={{ maxWidth: 900, margin: "0 auto" }}>
{/* Header */}
<motion.div
initial={{ opacity: 0, y: 20 }}
animate={inView ? { opacity: 1, y: 0 } : {}}
transition={{ duration: 0.6, ease: EASE }}
style={{ textAlign: "center", marginBottom: "3rem" }}
>
<span
style={{
display: "inline-flex",
alignItems: "center",
gap: 6,
padding: "0.375rem 0.875rem",
borderRadius: "var(--radius-full)",
border: "1px solid var(--color-border)",
background: "var(--color-background-card)",
fontSize: "0.8125rem",
fontWeight: 500,
color: "var(--color-foreground-muted)",
marginBottom: "1.25rem",
}}
>
<Terminal style={{ width: 14, height: 14, color: "var(--color-accent)" }} />
API v3
</span>
<h2
style={{
fontSize: "clamp(1.5rem, 3vw, 2.25rem)",
fontWeight: 700,
color: "var(--color-foreground)",
letterSpacing: "-0.02em",
marginBottom: "0.75rem",
}}
>
{title}
</h2>
<p style={{ fontSize: "1rem", color: "var(--color-foreground-muted)", lineHeight: 1.6, maxWidth: 480, margin: "0 auto" }}>
{subtitle}
</p>
</motion.div>
{/* API Cards grid */}
<div style={{ display: "grid", gridTemplateColumns: "repeat(auto-fill, minmax(380px, 1fr))", gap: 16, marginBottom: "2.5rem" }}>
{apis.map((api, i) => (
<motion.div
key={api.endpoint}
initial={{ opacity: 0, y: 20 }}
animate={inView ? { opacity: 1, y: 0 } : {}}
transition={{ duration: 0.5, delay: i * 0.1, ease: EASE }}
style={{
borderRadius: "var(--radius-lg)",
border: "1px solid var(--color-border)",
background: "var(--color-background-card)",
overflow: "hidden",
}}
>
{/* Card header */}
<div style={{ padding: "1rem 1.25rem", borderBottom: "1px solid var(--color-border)", display: "flex", alignItems: "center", justifyContent: "space-between" }}>
<div style={{ display: "flex", alignItems: "center", gap: 10 }}>
<span
style={{
padding: "0.2rem 0.5rem",
borderRadius: "var(--radius-sm)",
background: "var(--color-accent-subtle)",
fontSize: "0.6875rem",
fontWeight: 700,
fontFamily: "monospace",
color: methodColors[api.method] || "var(--color-foreground)",
}}
>
{api.method}
</span>
<code style={{ fontSize: "0.8125rem", color: "var(--color-foreground)", fontFamily: "monospace" }}>
{api.endpoint}
</code>
</div>
<span
style={{
padding: "0.2rem 0.5rem",
borderRadius: "var(--radius-full)",
fontSize: "0.625rem",
fontWeight: 600,
textTransform: "uppercase",
letterSpacing: "0.05em",
background: api.status === "beta" ? "var(--color-accent-subtle)" : "var(--color-background-alt)",
color: api.status === "beta" ? "var(--color-accent)" : "var(--color-foreground-muted)",
}}
>
{api.status}
</span>
</div>
{/* Description */}
<div style={{ padding: "1rem 1.25rem" }}>
<p style={{ fontSize: "0.875rem", fontWeight: 600, color: "var(--color-foreground)", marginBottom: 4 }}>
{api.name}
</p>
<p style={{ fontSize: "0.8125rem", color: "var(--color-foreground-muted)", lineHeight: 1.5 }}>
{api.description}
</p>
</div>
{/* Code snippet */}
<div
style={{
margin: "0 1.25rem 1rem",
padding: "0.75rem 1rem",
borderRadius: "var(--radius-md)",
background: "var(--color-background-alt)",
border: "1px solid var(--color-border)",
position: "relative",
}}
>
<pre style={{ fontSize: "0.75rem", color: "var(--color-foreground-muted)", fontFamily: "monospace", whiteSpace: "pre-wrap", wordBreak: "break-all", margin: 0, lineHeight: 1.5 }}>
{api.snippet}
</pre>
<button
onClick={() => handleCopy(api.snippet, i)}
style={{
position: "absolute",
top: 8,
right: 8,
padding: 4,
borderRadius: "var(--radius-sm)",
border: "none",
background: "transparent",
cursor: "pointer",
color: "var(--color-foreground-light)",
}}
aria-label="Copier"
>
{copiedIndex === i ? (
<Check style={{ width: 14, height: 14, color: "var(--color-accent)" }} />
) : (
<Copy style={{ width: 14, height: 14 }} />
)}
</button>
</div>
</motion.div>
))}
</div>
{/* Docs link */}
<div style={{ textAlign: "center" }}>
<a
href={docsLink}
style={{
display: "inline-flex",
alignItems: "center",
gap: 6,
padding: "0.75rem 1.5rem",
borderRadius: "var(--radius-md)",
border: "1px solid var(--color-border)",
background: "var(--color-background-card)",
fontSize: "0.875rem",
fontWeight: 600,
color: "var(--color-foreground)",
textDecoration: "none",
}}
>
<Code2 style={{ width: 16, height: 16, color: "var(--color-accent)" }} />
{docsLabel}
<ExternalLink style={{ width: 14, height: 14, color: "var(--color-foreground-light)" }} />
</a>
</div>
</div>
</section>
);
}
Autres variantes integrations
Integration Calendar
medium · both
minimalcorporate
Integration Chat Widget
medium · both
playfulminimal
Integration Flow Diagram
complex · both
elegantcorporate
Integration Grid Logos
simple · both
minimalcorporate
Integration Map Embed
medium · both
minimalcorporate
Integration Marketplace
complex · both
minimalelegant