2026-09-05 12:42:01 +02:00
|
|
|
import { motion, useReducedMotion } from "motion/react";
|
2026-08-06 08:36:47 +02:00
|
|
|
import { cn } from "@/lib/utils";
|
2026-09-05 12:42:01 +02:00
|
|
|
import { molla } from "@/lib/molla";
|
2026-08-06 08:36:47 +02:00
|
|
|
|
2026-09-05 12:42:01 +02:00
|
|
|
/**
|
|
|
|
|
* Barra di avanzamento a molla.
|
|
|
|
|
*
|
|
|
|
|
* Anima `scaleX` e non `width`: la larghezza rifà il layout a ogni frame,
|
|
|
|
|
* la trasformazione la gestisce il compositore. La molla riparte dal valore
|
|
|
|
|
* a schermo, quindi se il dato cambia a metà riempimento non c'è scatto.
|
|
|
|
|
*/
|
2026-08-06 08:36:47 +02:00
|
|
|
export function Barra({
|
|
|
|
|
percentuale,
|
|
|
|
|
className,
|
|
|
|
|
trackClassName,
|
|
|
|
|
altezza = "h-2",
|
|
|
|
|
}: {
|
|
|
|
|
percentuale: number;
|
|
|
|
|
className?: string;
|
|
|
|
|
trackClassName?: string;
|
|
|
|
|
altezza?: string;
|
|
|
|
|
}) {
|
2026-09-05 12:42:01 +02:00
|
|
|
const ridotto = useReducedMotion();
|
|
|
|
|
const valore = Math.max(0, Math.min(100, Math.round(percentuale)));
|
|
|
|
|
|
2026-08-06 08:36:47 +02:00
|
|
|
return (
|
2026-09-05 12:42:01 +02:00
|
|
|
<div
|
|
|
|
|
className={cn("overflow-hidden rounded-full bg-secondary", altezza, trackClassName)}
|
|
|
|
|
role="progressbar"
|
|
|
|
|
aria-valuenow={valore}
|
|
|
|
|
aria-valuemin={0}
|
|
|
|
|
aria-valuemax={100}
|
|
|
|
|
>
|
|
|
|
|
<motion.div
|
|
|
|
|
className={cn("h-full w-full origin-left rounded-full bg-accent-grad", className)}
|
|
|
|
|
initial={{ scaleX: 0 }}
|
|
|
|
|
animate={{ scaleX: valore / 100 }}
|
|
|
|
|
transition={ridotto ? { duration: 0.2 } : molla.ui}
|
2026-08-06 08:36:47 +02:00
|
|
|
/>
|
|
|
|
|
</div>
|
|
|
|
|
);
|
2026-09-01 13:38:33 +02:00
|
|
|
}
|