Retour au catalogue
Event Countdown Hero
Hero evenement avec grand compte a rebours anime, nom de l'evenement, date, lieu et CTA d'inscription.
eventmedium Both Responsive a11y
boldeleganteventeducationuniversalcentered
Theme
"use client";
import { useState, useEffect } from "react";
import { motion } from "framer-motion";
import { MapPin, CalendarDays } from "lucide-react";
interface EventCountdownHeroProps {
eventName?: string;
tagline?: string;
date?: string;
location?: string;
ctaLabel?: string;
ctaHref?: string;
targetDate?: string;
}
const EASE = [0.16, 1, 0.3, 1] as const;
function useCountdown(target: string) {
const [diff, setDiff] = useState({ days: 0, hours: 0, minutes: 0, seconds: 0 });
useEffect(() => {
const calc = () => {
const ms = Math.max(0, new Date(target).getTime() - Date.now());
setDiff({
days: Math.floor(ms / 86400000),
hours: Math.floor((ms % 86400000) / 3600000),
minutes: Math.floor((ms % 3600000) / 60000),
seconds: Math.floor((ms % 60000) / 1000),
});
};
calc();
const id = setInterval(calc, 1000);
return () => clearInterval(id);
}, [target]);
return diff;
}
const units = [
{ key: "days", label: "Jours" },
{ key: "hours", label: "Heures" },
{ key: "minutes", label: "Minutes" },
{ key: "seconds", label: "Secondes" },
] as const;
export default function EventCountdownHero({
eventName = "Sommet Digital 2026",
tagline = "L'evenement tech incontournable de l'annee",
date = "15 juin 2026",
location = "Palais des Congres, Paris",
ctaLabel = "Reserver ma place",
ctaHref = "#",
targetDate = "2026-06-15T09:00:00",
}: EventCountdownHeroProps) {
const countdown = useCountdown(targetDate);
return (
<section
style={{
padding: "var(--section-padding-y) 0",
background: "var(--color-background-dark, var(--color-background))",
minHeight: "70vh",
display: "flex", alignItems: "center",
}}
>
<div style={{ maxWidth: "var(--container-max-width)", margin: "0 auto", padding: "0 var(--container-padding-x)", width: "100%", textAlign: "center" }}>
<motion.div
initial={{ opacity: 0, y: 24 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.6, ease: EASE }}
>
<div style={{ display: "flex", justifyContent: "center", gap: "1.5rem", marginBottom: "1rem", flexWrap: "wrap" }}>
<span style={{ display: "inline-flex", alignItems: "center", gap: "0.35rem", fontSize: "0.875rem", color: "var(--color-foreground-on-dark, var(--color-foreground-muted))" }}>
<CalendarDays style={{ width: 14, height: 14 }} /> {date}
</span>
<span style={{ display: "inline-flex", alignItems: "center", gap: "0.35rem", fontSize: "0.875rem", color: "var(--color-foreground-on-dark, var(--color-foreground-muted))" }}>
<MapPin style={{ width: 14, height: 14 }} /> {location}
</span>
</div>
<h1 style={{
fontFamily: "var(--font-sans)",
fontSize: "clamp(2rem, 5vw, 3.5rem)",
fontWeight: 800,
color: "var(--color-foreground-on-dark, var(--color-foreground))",
marginBottom: "0.75rem",
letterSpacing: "-0.02em",
}}>
{eventName}
</h1>
{tagline && (
<p style={{ fontSize: "1.125rem", color: "var(--color-foreground-on-dark, var(--color-foreground-muted))", marginBottom: "2.5rem", maxWidth: "480px", margin: "0 auto 2.5rem" }}>
{tagline}
</p>
)}
</motion.div>
{/* Countdown */}
<motion.div
initial={{ opacity: 0, scale: 0.95 }}
animate={{ opacity: 1, scale: 1 }}
transition={{ duration: 0.5, delay: 0.2, ease: EASE }}
style={{ display: "flex", justifyContent: "center", gap: "clamp(0.75rem, 2vw, 1.5rem)", marginBottom: "2.5rem", flexWrap: "wrap" }}
>
{units.map((u) => (
<div key={u.key} style={{
width: "clamp(72px, 12vw, 100px)",
padding: "1rem 0.5rem",
borderRadius: "var(--radius-lg)",
background: "var(--color-background-alt)",
border: "1px solid var(--color-border)",
textAlign: "center",
}}>
<div style={{
fontFamily: "var(--font-mono, var(--font-sans))",
fontSize: "clamp(1.5rem, 3vw, 2.25rem)",
fontWeight: 700,
color: "var(--color-accent)",
lineHeight: 1,
}}>
{String(countdown[u.key]).padStart(2, "0")}
</div>
<div style={{ fontSize: "0.6875rem", color: "var(--color-foreground-muted)", marginTop: "0.35rem", textTransform: "uppercase", letterSpacing: "0.06em" }}>
{u.label}
</div>
</div>
))}
</motion.div>
<motion.a
href={ctaHref}
initial={{ opacity: 0, y: 12 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.4, delay: 0.35, ease: EASE }}
whileHover={{ scale: 1.03 }}
whileTap={{ scale: 0.97 }}
style={{
display: "inline-block",
padding: "0.875rem 2rem",
borderRadius: "var(--radius-md)",
background: "var(--color-accent)",
color: "var(--color-background)",
fontWeight: 600,
fontSize: "0.9375rem",
textDecoration: "none",
cursor: "pointer",
}}
>
{ctaLabel}
</motion.a>
</div>
</section>
);
}