mirror of
https://github.com/Rain-kl/OpenFlare.git
synced 2026-09-28 05:46:36 +08:00
451ce52592
Result: {"status":"keep","total_issues":8,"eslint_errors":0,"eslint_problems":0,"eslint_warnings":0,"golint_canonicalheader":0,"golint_errname":0,"golint_errorlint":1,"golint_exhaustive":0,"golint_forcetypeassert":0,"golint_gosec":0,"golint_intrange":0,"golint_modernize":3,"golint_nilnil":3,"golint_perfsprint":0,"golint_prealloc":0,"golint_recvcheck":1,"golint_test_testifylint":0,"golint_test_thelper":0,"golint_test_total":0,"golint_test_usetesting":0,"golint_total":8,"golint_usestdlibvars":0,"golint_vetx_total":0,"golint_wastedassign":0,"measure_s":93,"tsc_errors":0,"vitest_failed":0,"vitest_total":126}
140 lines
3.6 KiB
TypeScript
140 lines
3.6 KiB
TypeScript
import * as React from 'react';
|
|
import { motion } from 'motion/react';
|
|
import { cn } from '@/lib/utils';
|
|
import { FileTextIcon } from 'lucide-react';
|
|
|
|
/**
|
|
* 加载页面组件
|
|
*
|
|
* 用于统一显示加载状态
|
|
* @example
|
|
* ```tsx
|
|
* <LoadingPage text="系统" badgeText="系统" />
|
|
* ```
|
|
* @param {string} text - 显示的文本内容,默认为"系统"
|
|
* @param {string} badgeText - 显示的徽章文本,默认为"系统"
|
|
* @returns {React.ReactNode} 加载页面组件
|
|
*/
|
|
|
|
export function AppleSpinner({
|
|
className = 'size-8 text-muted-foreground',
|
|
}: {
|
|
className?: string;
|
|
}) {
|
|
const spokes = Array.from({ length: 12 });
|
|
return (
|
|
<div className={cn('relative flex items-center justify-center', className)}>
|
|
<style
|
|
dangerouslySetInnerHTML={{
|
|
__html: `
|
|
@keyframes apple-spinner-fade {
|
|
0% { opacity: 1; }
|
|
100% { opacity: 0.15; }
|
|
}
|
|
.apple-spinner-spoke {
|
|
animation: apple-spinner-fade 1.2s linear infinite;
|
|
}
|
|
`,
|
|
}}
|
|
/>
|
|
<div className='relative size-full'>
|
|
{spokes.map((_, i) => (
|
|
<div
|
|
key={i}
|
|
className='apple-spinner-spoke absolute top-0 left-[46%] w-[8%] h-[28%] bg-current rounded-full'
|
|
style={{
|
|
transform: `rotate(${i * 30}deg)`,
|
|
transformOrigin: '50% 178.5%',
|
|
animationDelay: `${(i - 12) * 0.1}s`,
|
|
}}
|
|
/>
|
|
))}
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
/**
|
|
* 加载页面组件
|
|
*
|
|
* 用于统一显示加载状态
|
|
*/
|
|
export function LoadingPage(props: { text?: string; badgeText?: string }) {
|
|
const _ = props;
|
|
return (
|
|
<div className='absolute inset-0 z-50 overflow-hidden font-sans bg-background/80 backdrop-blur-md text-foreground flex items-center justify-center'>
|
|
<motion.div
|
|
initial={{ opacity: 0, scale: 0.96 }}
|
|
animate={{ opacity: 1, scale: 1 }}
|
|
transition={{ duration: 0.25, ease: 'easeOut' }}
|
|
className='flex items-center justify-center'
|
|
>
|
|
<AppleSpinner className='size-9 text-muted-foreground/80' />
|
|
</motion.div>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
interface LoadingStateProps extends React.ComponentProps<'div'> {
|
|
title?: string;
|
|
description?: string;
|
|
icon?: React.ComponentType<{ className?: string }>;
|
|
iconSize?: 'sm' | 'md' | 'lg';
|
|
}
|
|
|
|
/**
|
|
* 加载状态展示组件
|
|
* 用于统一显示加载中的状态
|
|
*/
|
|
export function LoadingState({
|
|
title = '加载中',
|
|
description = '正在获取活动数据...',
|
|
icon: Icon = FileTextIcon,
|
|
className,
|
|
iconSize = 'md',
|
|
}: LoadingStateProps) {
|
|
const iconSizes = { sm: 'size-8', md: 'size-10', lg: 'size-14' };
|
|
const iconInnerSizes = { sm: 'size-4', md: 'size-5', lg: 'size-7' };
|
|
|
|
return (
|
|
<div
|
|
className={cn(
|
|
'flex flex-col items-center justify-center py-12 text-center',
|
|
className,
|
|
)}
|
|
>
|
|
<div
|
|
className={cn(
|
|
'rounded-full bg-muted flex items-center justify-center mb-2 animate-pulse',
|
|
iconSizes[iconSize],
|
|
)}
|
|
>
|
|
<Icon
|
|
className={cn('text-muted-foreground', iconInnerSizes[iconSize])}
|
|
/>
|
|
</div>
|
|
|
|
{title && (
|
|
<p className='text-sm font-medium mb-1 animate-pulse'>{title}</p>
|
|
)}
|
|
|
|
{description && (
|
|
<p className='text-xs text-muted-foreground max-w-md animate-pulse'>
|
|
{description}
|
|
</p>
|
|
)}
|
|
</div>
|
|
);
|
|
}
|
|
|
|
/**
|
|
* 带边框的加载状态组件
|
|
*/
|
|
export function LoadingStateWithBorder(props: LoadingStateProps) {
|
|
return (
|
|
<div className='border border-dashed rounded-lg'>
|
|
<LoadingState {...props} />
|
|
</div>
|
|
);
|
|
}
|