129 lines
3.7 KiB
TypeScript
129 lines
3.7 KiB
TypeScript
// import React from 'react';
|
|
|
|
interface SkeletonBarProps {
|
|
width?: string;
|
|
height?: string;
|
|
className?: string;
|
|
}
|
|
|
|
// 基础骨架条
|
|
export function SkeletonBar({ width = 'w-full', height = 'h-5', className = '' }: SkeletonBarProps) {
|
|
return (
|
|
<div className={`${width} ${height} bg-gray-200 rounded-md animate-pulse ${className}`}></div>
|
|
);
|
|
}
|
|
|
|
// 通用骨架屏
|
|
export function SkeletonScreen() {
|
|
return (
|
|
<div className="flex flex-col gap-4">
|
|
<SkeletonBar height="h-10" />
|
|
<SkeletonBar height="h-10" />
|
|
<SkeletonBar height="h-10" />
|
|
</div>
|
|
);
|
|
}
|
|
|
|
// 数字统计骨架
|
|
export function NumberSkeleton({ className = '' }: { className?: string }) {
|
|
return (
|
|
<SkeletonBar width="w-12" height="h-5" className={className} />
|
|
);
|
|
}
|
|
|
|
// 表格行骨架屏
|
|
interface TableRowSkeletonProps {
|
|
count?: number;
|
|
className?: string;
|
|
}
|
|
|
|
export function TableRowSkeleton({ count = 5, className = '' }: TableRowSkeletonProps) {
|
|
return (
|
|
<div className={`py-2 ${className}`}>
|
|
{Array(count).fill(0).map((_, index) => (
|
|
<div key={index} className="flex items-center p-4 border-b border-gray-100">
|
|
<div className="w-[30%] flex">
|
|
<SkeletonBar width="w-10" height="h-10" />
|
|
<div className="ml-2">
|
|
<SkeletonBar width="w-48" className="mb-2" />
|
|
<SkeletonBar width="w-32" height="h-3" />
|
|
</div>
|
|
</div>
|
|
<div className="w-[12%]">
|
|
<SkeletonBar width="w-20" height="h-6" />
|
|
</div>
|
|
<div className="w-[12%]">
|
|
<SkeletonBar width="w-24" className="mb-1" />
|
|
<SkeletonBar width="w-16" height="h-3" />
|
|
</div>
|
|
<div className="w-[12%]">
|
|
<SkeletonBar width="w-16" height="h-5" className="mb-1" />
|
|
<SkeletonBar width="w-16" height="h-5" />
|
|
</div>
|
|
<div className="w-[20%]">
|
|
<SkeletonBar width="w-32" className="mb-1" />
|
|
<SkeletonBar width="w-24" />
|
|
</div>
|
|
<div className="w-[14%]">
|
|
<SkeletonBar width="w-16" height="h-8" />
|
|
</div>
|
|
</div>
|
|
))}
|
|
</div>
|
|
);
|
|
}
|
|
|
|
// 自定义列宽的表格行骨架屏
|
|
interface CustomTableRowSkeletonProps {
|
|
count?: number;
|
|
columns: Array<{
|
|
width: string;
|
|
rows?: Array<{
|
|
width: string;
|
|
height?: string;
|
|
className?: string;
|
|
}>;
|
|
}>;
|
|
className?: string;
|
|
}
|
|
|
|
export function CustomTableRowSkeleton({ count = 5, columns, className = '' }: CustomTableRowSkeletonProps) {
|
|
return (
|
|
<div className={`py-2 ${className}`}>
|
|
{Array(count).fill(0).map((_, rowIndex) => (
|
|
<div key={rowIndex} className="flex items-center p-4 border-b border-gray-100">
|
|
{columns.map((column, colIndex) => (
|
|
<div key={colIndex} className={`${column.width}`}>
|
|
{column.rows ? (
|
|
column.rows.map((row, rowIdx) => (
|
|
<SkeletonBar
|
|
key={rowIdx}
|
|
width={row.width}
|
|
height={row.height || 'h-4'}
|
|
className={`${rowIdx < column.rows!.length - 1 ? 'mb-1' : ''} ${row.className || ''}`}
|
|
/>
|
|
))
|
|
) : (
|
|
<SkeletonBar width="w-full" />
|
|
)}
|
|
</div>
|
|
))}
|
|
</div>
|
|
))}
|
|
</div>
|
|
);
|
|
}
|
|
|
|
// 加载指示器
|
|
export function LoadingIndicator({ text = '正在加载数据...' }: { text?: string }) {
|
|
return (
|
|
<div className="py-4 flex justify-center items-center">
|
|
<div className="animate-spin rounded-full h-6 w-6 border-b-2 border-green-700 mr-2"></div>
|
|
<span className="text-sm text-gray-500">{text}</span>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
|
|
|