Retour au catalogue
Feature Showcase Holographic
Cartes holographiques avec effet flip 3D pour reveler les details de chaque feature.
feature-showcasecomplex Both Responsive a11y
boldelegantsaasagencygrid
Theme
"use client";
import { useState } from "react";
import { motion } from "framer-motion";
import {
Cpu,
Eye,
Lock,
Workflow,
Database,
Layers,
type LucideIcon,
} from "lucide-react";
const iconMap: Record<string, LucideIcon> = {
Cpu,
Eye,
Lock,
Workflow,
Database,
Layers,
};
interface HoloFeature {
icon: string;
title: string;
frontText: string;
backText: string;
}
interface FeatureShowcaseHolographicProps {
title?: string;
subtitle?: string;
features?: HoloFeature[];
}
const EASE = [0.16, 1, 0.3, 1] as const;
function HoloCard({ feature, index }: { feature: HoloFeature; index: number }) {
const [isFlipped, setIsFlipped] = useState(false);
const [mousePos, setMousePos] = useState({ x: 0.5, y: 0.5 });
const Icon = iconMap[feature.icon] || Cpu;
function handleMouseMove(e: React.MouseEvent<HTMLDivElement>) {
const rect = e.currentTarget.getBoundingClientRect();
setMousePos({
x: (e.clientX - rect.left) / rect.width,
y: (e.clientY - rect.top) / rect.height,
});
}
const gradientAngle = Math.atan2(mousePos.y - 0.5, mousePos.x - 0.5) * (180 / Math.PI);
return (
<motion.div
initial={{ opacity: 0, y: 24 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true }}
transition={{ duration: 0.5, delay: 0.07 * index, ease: EASE }}
onClick={() => setIsFlipped((f) => !f)}
onMouseMove={handleMouseMove}
style={{
perspective: 1000,
cursor: "pointer",
minHeight: 260,
}}
>
<motion.div
animate={{ rotateY: isFlipped ? 180 : 0 }}
transition={{ duration: 0.6, ease: EASE }}
style={{
position: "relative",
width: "100%",
height: "100%",
minHeight: 260,
transformStyle: "preserve-3d",
}}
>
{/* Front face */}
<div
style={{
position: "absolute",
inset: 0,
backfaceVisibility: "hidden",
borderRadius: "var(--radius-lg)",
border: "1px solid var(--color-border)",
background: "var(--color-background-card)",
padding: "2rem 1.5rem",
display: "flex",
flexDirection: "column",
alignItems: "center",
justifyContent: "center",
textAlign: "center",
overflow: "hidden",
}}
>
{/* Holographic sheen overlay */}
<div
style={{
position: "absolute",
inset: 0,
background: `linear-gradient(${gradientAngle}deg,
color-mix(in srgb, var(--color-accent) 8%, transparent) 0%,
transparent 40%,
color-mix(in srgb, var(--color-accent) 5%, transparent) 70%,
transparent 100%)`,
pointerEvents: "none",
transition: "background 0.15s ease",
}}
/>
<div
style={{
width: 56,
height: 56,
borderRadius: "var(--radius-md)",
background: "var(--color-accent-subtle)",
display: "flex",
alignItems: "center",
justifyContent: "center",
marginBottom: "1.25rem",
}}
>
<Icon style={{ width: 28, height: 28, color: "var(--color-accent)" }} />
</div>
<h3
style={{
fontSize: "1.125rem",
fontWeight: 700,
color: "var(--color-foreground)",
marginBottom: "0.5rem",
}}
>
{feature.title}
</h3>
<p
style={{
fontSize: "0.875rem",
color: "var(--color-foreground-muted)",
lineHeight: 1.6,
}}
>
{feature.frontText}
</p>
<span
style={{
marginTop: "1rem",
fontSize: "0.75rem",
color: "var(--color-accent)",
fontWeight: 600,
}}
>
Cliquez pour en savoir plus
</span>
</div>
{/* Back face */}
<div
style={{
position: "absolute",
inset: 0,
backfaceVisibility: "hidden",
transform: "rotateY(180deg)",
borderRadius: "var(--radius-lg)",
border: "1px solid var(--color-accent)",
background: "var(--color-background-alt)",
padding: "2rem 1.5rem",
display: "flex",
flexDirection: "column",
alignItems: "center",
justifyContent: "center",
textAlign: "center",
}}
>
<Icon
style={{
width: 24,
height: 24,
color: "var(--color-accent)",
marginBottom: "1rem",
}}
/>
<h3
style={{
fontSize: "1rem",
fontWeight: 700,
color: "var(--color-foreground)",
marginBottom: "0.75rem",
}}
>
{feature.title}
</h3>
<p
style={{
fontSize: "0.8125rem",
color: "var(--color-foreground-muted)",
lineHeight: 1.7,
}}
>
{feature.backText}
</p>
</div>
</motion.div>
</motion.div>
);
}
export default function FeatureShowcaseHolographic({
title = "Technologies de pointe",
subtitle = "Fonctionnalites",
features = [],
}: FeatureShowcaseHolographicProps) {
return (
<section
style={{
paddingTop: "var(--section-padding-y)",
paddingBottom: "var(--section-padding-y)",
background: "var(--color-background)",
}}
>
<div
style={{
maxWidth: "var(--container-max-width)",
margin: "0 auto",
padding: "0 var(--container-padding-x)",
}}
>
<motion.div
initial={{ opacity: 0, y: 16 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true }}
transition={{ duration: 0.5, ease: EASE }}
style={{ textAlign: "center", marginBottom: "3rem" }}
>
<p
style={{
fontSize: "0.75rem",
fontWeight: 600,
textTransform: "uppercase",
letterSpacing: "0.1em",
color: "var(--color-accent)",
marginBottom: "0.5rem",
}}
>
{subtitle}
</p>
<h2
style={{
fontSize: "clamp(1.75rem, 3vw, 2.5rem)",
fontWeight: 700,
color: "var(--color-foreground)",
}}
>
{title}
</h2>
</motion.div>
<div
style={{
display: "grid",
gridTemplateColumns: "repeat(auto-fit, minmax(280px, 1fr))",
gap: "1.5rem",
}}
>
{features.map((feature, i) => (
<HoloCard key={i} feature={feature} index={i} />
))}
</div>
</div>
</section>
);
}