返回 AiToEarn
spin.tsx
1 /**
2 * Spin - 加载中组件
3 * 用于显示加载状态
4 */
5
6 'use client'
7
8 import { cn } from '@/utils/className'
9
10 interface SpinProps {
11 /** 是否显示加载状态 */
12 spinning?: boolean
13 /** 子元素 */
14 children?: React.ReactNode
15 /** 自定义类名 */
16 className?: string
17 /** 提示文字 */
18 tip?: string
19 }
20
21 export function Spin({ spinning = false, children, className, tip }: SpinProps) {
22 if (!spinning && !children) {
23 return null
24 }
25
26 const spinner = (
27 <div className="flex flex-col items-center justify-center gap-2">
28 <svg
29 className="animate-spin h-5 w-5 text-foreground"
30 xmlns="http://www.w3.org/2000/svg"
31 fill="none"
32 viewBox="0 0 24 24"
33 >
34 <circle
35 className="opacity-25"
36 cx="12"
37 cy="12"
38 r="10"
39 stroke="currentColor"
40 strokeWidth="4"
41 />
42 <path
43 className="opacity-75"
44 fill="currentColor"
45 d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"
46 />
47 </svg>
48 {tip && <span className="text-sm text-muted-foreground">{tip}</span>}
49 </div>
50 )
51
52 if (!children) {
53 return <div className={cn('flex items-center justify-center p-4', className)}>{spinner}</div>
54 }
55
56 return (
57 <div className={cn('relative', className)}>
58 {spinning && (
59 <div className="absolute inset-0 z-10 flex items-center justify-center bg-background/50 backdrop-blur-sm rounded">
60 {spinner}
61 </div>
62 )}
63 {children}
64 </div>
65 )
66 }
67
67 lines Plain Text