css transition не поддерживает анимацию градиентов.
На js это можно реализовать с помощью requestAnimationFrame
const lerp = (a, b, t) => a * (1 - t) + b * t;
// from: https://easings.net
const easeOutQuad = (x) => 1 - (1 - x) * (1 - x);
function tween(from, to, duration, onUpdate, easeFn) {
let rafId = null;
let begin;
const loop = (now) => {
begin ??= now;
const progress = Math.min(1, (now - begin) / duration);
const ease = easeFn ? easeFn(progress) : progress;
const val = lerp(from, to, ease);
onUpdate(val);
if (progress === 1) {
rafId = null;
return;
}
rafId = requestAnimationFrame(loop);
};
rafId = requestAnimationFrame(loop);
return () => rafId ?? cancelAnimationFrame(rafId);
}
const progressBar = document.querySelector(".progressbar");
const progressBarValue = document.querySelector(".progressbar__value");
const progressBarStartValue = 0;
const progressBarEndValue = 100;
const progressBarStep = 10;
const animationDuration = 1000;
let progressBarCurrentValue = progressBarStartValue;
let killTween = null;
function onUpdate(val) {
progressBarValue.textContent = `${val.toFixed(1)}%`;
progressBar.style.background = `conic-gradient(#FFF ${val * 3.6}deg, #262623 ${val * 3.6}deg)`;
if (val === progressBarEndValue) {
alert("you have completed all the tasks");
}
}
document.body.addEventListener("click", (e) => {
if (progressBarCurrentValue === progressBarEndValue) {
alert("you have completed all the tasks");
} else {
const fromValue = progressBarCurrentValue;
progressBarCurrentValue = Math.min(
progressBarEndValue,
progressBarCurrentValue + progressBarStep
);
killTween?.();
killTween = tween(
fromValue,
progressBarCurrentValue,
animationDuration,
onUpdate,
easeOutQuad
);
}
});