You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
85 lines
2.6 KiB
85 lines
2.6 KiB
import { a, to, useSpring } from "@react-spring/web"; |
|
import classNames from "classnames"; |
|
|
|
import { Icon, Icons } from "@/components/Icon"; |
|
import { Transition } from "@/components/utils/Transition"; |
|
|
|
export interface StatusCircle { |
|
type: "loading" | "success" | "error" | "noresult" | "waiting"; |
|
percentage?: number; |
|
} |
|
|
|
export interface StatusCircleLoading extends StatusCircle { |
|
type: "loading"; |
|
percentage: number; |
|
} |
|
|
|
function statusIsLoading( |
|
props: StatusCircle | StatusCircleLoading |
|
): props is StatusCircleLoading { |
|
return props.type === "loading"; |
|
} |
|
|
|
export function StatusCircle(props: StatusCircle | StatusCircleLoading) { |
|
const [spring] = useSpring( |
|
() => ({ |
|
percentage: statusIsLoading(props) ? props.percentage : 0, |
|
}), |
|
[props] |
|
); |
|
|
|
return ( |
|
<div |
|
className={classNames({ |
|
"p-0.5 border-current border-[3px] rounded-full h-6 w-6 relative transition-colors": |
|
true, |
|
"text-video-scraping-loading": props.type === "loading", |
|
"text-video-scraping-noresult text-opacity-50": |
|
props.type === "waiting", |
|
"text-video-scraping-error bg-video-scraping-error": |
|
props.type === "error", |
|
"text-green-500 bg-green-500": props.type === "success", |
|
"text-video-scraping-noresult bg-video-scraping-noresult": |
|
props.type === "noresult", |
|
})} |
|
> |
|
<Transition animation="fade" show={statusIsLoading(props)}> |
|
<svg |
|
width="100%" |
|
height="100%" |
|
viewBox="0 0 64 64" |
|
xmlns="http://www.w3.org/2000/svg" |
|
className="rounded-full -rotate-90" |
|
> |
|
<a.circle |
|
strokeWidth="32" |
|
strokeDasharray={to(spring.percentage, (val) => `${val} 100`)} |
|
r="25%" |
|
cx="50%" |
|
cy="50%" |
|
fill="transparent" |
|
stroke="currentColor" |
|
className="transition-[strokeDasharray]" |
|
/> |
|
</svg> |
|
</Transition> |
|
<Transition animation="fade" show={props.type === "error"}> |
|
<Icon |
|
className="absolute inset-0 flex items-center justify-center text-white" |
|
icon={Icons.X} |
|
/> |
|
</Transition> |
|
<Transition animation="fade" show={props.type === "success"}> |
|
<Icon |
|
className="absolute inset-0 flex items-center text-xs justify-center text-white" |
|
icon={Icons.CHECKMARK} |
|
/> |
|
</Transition> |
|
<Transition animation="fade" show={props.type === "noresult"}> |
|
<div className="absolute inset-0 flex items-center"> |
|
<div className="h-[3px] flex-1 mx-1 rounded-full bg-background-main" /> |
|
</div> |
|
</Transition> |
|
</div> |
|
); |
|
}
|
|
|