Retour au catalogue
Loading Progress Bar
Barre de progression avec etapes textuelles, spinner et pourcentage.
loading-statessimple Both Responsive a11y
minimalsaasuniversalcentered
Theme
"use client";
import { useState, useEffect } from "react";
import { motion } from "framer-motion";
interface LoadingProgressBarProps {
label?: string;
steps?: string[];
duration?: number;
}
export default function LoadingProgressBar({
label = "Chargement...",
steps = [],
duration = 3000,
}: LoadingProgressBarProps) {
const [progress, setProgress] = useState(0);
const [stepIndex, setStepIndex] = useState(0);
useEffect(() => {
const interval = setInterval(() => {
setProgress((prev) => {
const next = prev + 2;
if (next >= 100) { clearInterval(interval); return 100; }
return next;
});
}, duration / 50);
return () => clearInterval(interval);
}, [duration]);
useEffect(() => {
if (steps.length === 0) return;
const stepSize = 100 / steps.length;
setStepIndex(Math.min(Math.floor(progress / stepSize), steps.length - 1));
}, [progress, steps]);
return (
<div className="py-20 px-6" style={{ background: "var(--color-background)" }}>
<div className="mx-auto max-w-sm text-center">
<div className="mb-4">
<motion.div
animate={{ rotate: 360 }}
transition={{ duration: 2, repeat: Infinity, ease: "linear" }}
className="inline-block w-8 h-8 rounded-full"
style={{ border: "2px solid var(--color-border)", borderTopColor: "var(--color-accent)" }}
/>
</div>
<h3 className="text-sm font-semibold mb-1" style={{ color: "var(--color-foreground)" }}>{label}</h3>
{steps.length > 0 && (
<p className="text-xs mb-4" style={{ color: "var(--color-foreground-muted)" }}>{steps[stepIndex]}</p>
)}
<div className="h-2 rounded-full overflow-hidden mb-2" style={{ background: "var(--color-background-alt)" }}>
<motion.div className="h-full rounded-full" style={{ background: "var(--color-accent)" }} animate={{ width: `${progress}%` }} transition={{ duration: 0.1 }} />
</div>
<span className="text-xs font-medium" style={{ color: "var(--color-foreground-light)" }}>{progress}%</span>
</div>
</div>
);
}