video-flow-b/components/common/GlobalLoad.tsx
2025-09-15 11:21:48 +08:00

138 lines
3.9 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { Spin } from "antd";
import { ReactNode } from "react";
interface GlobalLoadProps {
/** 是否显示加载状态 */
show: boolean;
/** 子元素内容 */
children?: ReactNode;
/** 进度条数值 0-100非必须 */
progress?: number;
/** 旋转圆环直径,非必须 */
spinnerDiameter?: number;
/** 进度条宽度,非必须 */
progressWidth?: number;
/** 是否显示旋转圆圈,默认显示 */
showSpinner?: boolean;
}
/**
* 全局加载组件,支持标签包裹形式渲染子元素
* @param props - 组件属性
* @returns 加载组件
*/
export default function GlobalLoad({
show,
children=<></>,
progress,
spinnerDiameter,
progressWidth,
showSpinner = true,
}: GlobalLoadProps) {
if (!show) {
return <>{children}</>;
}
// 自定义加载图标:组合两个组件
const customIndicator = (
<div
data-alt="custom-loading-indicator"
className="!w-max !h-max !flex flex-col items-center justify-center -translate-x-1/2"
>
{showSpinner && <TailwindSpinner diameter={spinnerDiameter} />}
{Boolean(progress) && <TailwindLinearLoader progress={progress as number} width={progressWidth} />}
</div>
);
return (
<div data-alt="loading-container" className="relative">
<Spin spinning={true} tip="" indicator={customIndicator}>
{children}
</Spin>
</div>
);
}
/**
* Tailwind CSS loading spinner component for global loading overlay.
* @param diameter - Diameter of the spinner in pixels
* @returns {JSX.Element} - Spinner visual.
*/
export const TailwindSpinner = ({ diameter = 50 }: { diameter?: number }) => {
const radius = diameter / 2;
return (
<div data-alt="loading-spinner" className="relative" style={{ width: `${diameter}px`, height: `${diameter}px` }}>
{/* 主旋转圆环 */}
<div
className="w-full h-full animate-spin"
style={{
width: `${diameter}px`,
height: `${diameter}px`,
borderRadius: `${radius}px`,
backgroundImage:
"linear-gradient(rgb(186, 66, 255) 35%, rgb(0, 225, 255))",
filter: "blur(1px)",
boxShadow:
"0px -5px 20px 0px rgb(186, 66, 255), 0px 5px 20px 0px rgb(0, 225, 255)",
animation: "spinning82341 1.7s linear infinite",
}}
data-alt="spinner-main"
/>
{/* 背景模糊圆环 */}
<div
className="absolute inset-0"
style={{
width: `${diameter}px`,
height: `${diameter}px`,
borderRadius: `${radius}px`,
backgroundColor: "rgb(36, 36, 36)",
filter: "blur(10px)",
}}
data-alt="spinner-blur-bg"
/>
{/* 自定义动画关键帧 */}
<style>
{`
@keyframes spinning82341 {
to {
transform: rotate(360deg);
}
}
`}
</style>
</div>
);
};
/**
* Tailwind CSS linear progress bar loader with animated light sweep.
* @param progress - Progress value from 0 to 100
* @param width - Width of the progress bar in pixels
* @returns {JSX.Element} - Linear loader visual.
*/
export const TailwindLinearLoader = ({
progress,
width = 160
}: {
progress: number;
width?: number;
}) => (
<div
data-alt="linear-loader-container"
className="relative h-[2px] bg-gray-200 dark:bg-gray-700 overflow-hidden rounded-full"
style={{ width: `${width}px` }}
>
{/* Animated light sweep - position controlled by progress */}
<div
data-alt="linear-loader-light"
className="absolute top-0 h-full w-[70px]"
style={{
background:
"linear-gradient(87deg, rgba(0, 0, 0, 0) 0%, rgb(0, 204, 255) 40%, rgb(0, 204, 255) 60%, rgba(0, 0, 0, 0) 100%)",
left: `${progress - 10}%`,
}}
/>
{/* Keyframes for light sweep - no longer needed since position is controlled by progress */}
</div>
);