Files
mixvideo-v2/apps/desktop/src/components/LoadingSpinner.tsx
imeepos c366261008 feat: UI美化和UX改进 v0.1.5
- 优化设计系统和主题配置
  - 增强Tailwind配置,添加更丰富的色彩系统
  - 新增多种动画效果和过渡动画
  - 改进字体系统和间距设置
  - 添加阴影变体和渐变效果

- 改进项目列表页面UI/UX
  - 重新设计页面头部,添加渐变背景和统计信息
  - 优化项目卡片布局和响应式设计
  - 增强加载和错误状态的视觉效果
  - 添加交错动画效果

- 优化项目卡片组件
  - 重新设计卡片布局,添加背景装饰
  - 改进统计信息展示,使用渐变背景和徽章
  - 增强悬停效果和交互反馈
  - 优化菜单和按钮设计

- 改进表单和模态框体验
  - 重新设计模态框头部和布局
  - 增强表单字段的视觉设计和验证反馈
  - 添加加载状态和成功状态指示
  - 改进按钮样式和交互效果

- 增强加载状态和反馈机制
  - 重新设计EmptyState组件,添加装饰效果
  - 增强LoadingSpinner,支持多种动画样式
  - 改进ErrorMessage组件,支持多种消息类型
  - 新增SkeletonLoader组件用于骨架屏加载

- 添加微交互和动画效果
  - 新增AnimatedButton组件,支持涟漪效果
  - 创建PageTransition组件用于页面过渡
  - 添加多种动画工具组件
  - 增强按钮和卡片的微交互效果

- 优化响应式设计和移动端体验
  - 改进容器布局和间距设置
  - 优化移动端的触摸体验
  - 确保所有组件在不同屏幕尺寸下的完美适配

遵循前端开发规范,提升界面美观性和用户体验
2025-07-14 00:23:58 +08:00

120 lines
3.2 KiB
TypeScript

import React from 'react';
import { Loader2, Circle } from 'lucide-react';
interface LoadingSpinnerProps {
size?: 'small' | 'medium' | 'large';
text?: string;
variant?: 'spinner' | 'dots' | 'pulse' | 'bars';
color?: 'primary' | 'secondary' | 'white';
}
/**
* 增强的加载动画组件
* 支持多种动画样式和尺寸
*/
export const LoadingSpinner: React.FC<LoadingSpinnerProps> = ({
size = 'medium',
text,
variant = 'spinner',
color = 'primary'
}) => {
const sizeMap = {
small: { icon: 16, text: 'text-sm', padding: 'p-3' },
medium: { icon: 24, text: 'text-base', padding: 'p-6' },
large: { icon: 32, text: 'text-lg', padding: 'p-8' }
};
const colorMap = {
primary: 'text-primary-600',
secondary: 'text-gray-600',
white: 'text-white'
};
const currentSize = sizeMap[size];
const currentColor = colorMap[color];
const renderSpinner = () => {
switch (variant) {
case 'dots':
return (
<div className="flex space-x-1">
{[0, 1, 2].map((i) => (
<Circle
key={i}
size={currentSize.icon / 3}
className={`${currentColor} animate-loading-dots`}
style={{ animationDelay: `${i * 0.2}s` }}
fill="currentColor"
/>
))}
</div>
);
case 'pulse':
return (
<div className={`w-${currentSize.icon / 4} h-${currentSize.icon / 4} ${currentColor.replace('text-', 'bg-')} rounded-full animate-pulse-slow`} />
);
case 'bars':
return (
<div className="flex space-x-1">
{[0, 1, 2, 3].map((i) => (
<div
key={i}
className={`w-1 h-${currentSize.icon / 4} ${currentColor.replace('text-', 'bg-')} animate-loading-bars`}
style={{ animationDelay: `${i * 0.1}s` }}
/>
))}
</div>
);
default:
return (
<Loader2
size={currentSize.icon}
className={`animate-spin ${currentColor}`}
/>
);
}
};
return (
<div className={`flex flex-col items-center justify-center gap-4 ${currentSize.padding} animate-fade-in`}>
{/* 加载动画 */}
<div className="relative">
{/* 背景光晕效果 */}
{color === 'primary' && (
<div className="absolute inset-0 bg-primary-200 rounded-full blur-lg opacity-30 animate-pulse"></div>
)}
{/* 主要动画 */}
<div className="relative">
{renderSpinner()}
</div>
</div>
{/* 加载文本 */}
{text && (
<div className="text-center">
<span className={`${currentColor} ${currentSize.text} font-medium animate-pulse`}>
{text}
</span>
{/* 动态点点点效果 */}
<span className="inline-flex ml-1">
{[0, 1, 2].map((i) => (
<span
key={i}
className={`${currentColor} animate-pulse`}
style={{ animationDelay: `${i * 0.3}s` }}
>
.
</span>
))}
</span>
</div>
)}
</div>
);
};