373fc0496c
统一简化多个页面里的CopyButton调用,删除不再需要的空回调参数 * feat: 添加clearCookies函数的单元测试并修复cookie域名处理逻辑 * feat: 增强 data URI 处理,支持带参数的前缀并更新相关测试 * fix: 修正 AGENTS.md 中 TypeScript 类型检查命令的描述 * feat: 添加 settings.local.json 文件以配置 Bash 权限 * perf: 预设背景色避免 Popup 弹窗白屏闪烁 * perf: 避免图标过早实例化,传递组件引用而非 JSX 节点 * feat: 添加 useLazyTranslation 和 preloadNamespaces 函数以支持动态加载 i18n 命名空间 * feat: 使用 useLazyTranslation 替换 useTranslation 以支持懒加载翻译 * feat: 添加 PageSkeleton 组件及其测试用例以支持页面加载骨架屏 * feat: 使用骨架屏替换加载状态指示器,优化用户体验 * feat: 优化 CopyButton 组件的复制功能,添加定时器管理复制状态 * feat: 调整 chunk 大小警告阈值以优化构建性能
104 lines
2.7 KiB
TypeScript
104 lines
2.7 KiB
TypeScript
/**
|
|
* PageSkeleton 组件 - 页面加载骨架屏
|
|
*
|
|
* 用于 Suspense fallback 和初始加载状态,提供平滑的视觉过渡
|
|
* 避免白屏闪烁,减少布局偏移
|
|
*/
|
|
import { Box, Skeleton, Stack, useTheme } from '@mui/material';
|
|
import { alpha } from '@mui/material';
|
|
|
|
interface PageSkeletonProps {
|
|
/** 骨架屏类型 */
|
|
variant?: 'dashboard' | 'tool';
|
|
}
|
|
|
|
/**
|
|
* 仪表盘卡片骨架屏
|
|
*/
|
|
function DashboardCardSkeleton() {
|
|
const theme = useTheme();
|
|
const borderColor = alpha(theme.palette.divider, 0.5);
|
|
|
|
return (
|
|
<Box
|
|
sx={{
|
|
borderRadius: 4,
|
|
border: '1px solid',
|
|
borderColor,
|
|
p: 2.5,
|
|
height: 100,
|
|
}}
|
|
>
|
|
<Stack direction="row" justifyContent="space-between" alignItems="flex-start">
|
|
<Stack direction="row" spacing={1.5} alignItems="center">
|
|
<Skeleton variant="rounded" width={40} height={40} sx={{ borderRadius: 3 }} />
|
|
<Box>
|
|
<Skeleton variant="text" width={100} height={20} />
|
|
<Skeleton variant="text" width={140} height={14} sx={{ mt: 0.5 }} />
|
|
</Box>
|
|
</Stack>
|
|
<Skeleton variant="circular" width={12} height={12} />
|
|
</Stack>
|
|
</Box>
|
|
);
|
|
}
|
|
|
|
/**
|
|
* 工具页面骨架屏
|
|
*/
|
|
function ToolPageSkeleton() {
|
|
return (
|
|
<Box sx={{ p: 2.5 }}>
|
|
{/* 标题区域 */}
|
|
<Skeleton variant="text" width={180} height={28} sx={{ mb: 2 }} />
|
|
|
|
{/* 输入区域 */}
|
|
<Skeleton variant="rounded" width="100%" height={120} sx={{ borderRadius: 3, mb: 2 }} />
|
|
|
|
{/* 控制栏 */}
|
|
<Stack direction="row" spacing={1} sx={{ mb: 2 }}>
|
|
<Skeleton variant="rounded" width={100} height={36} sx={{ borderRadius: 2 }} />
|
|
<Skeleton variant="rounded" width={80} height={36} sx={{ borderRadius: 2 }} />
|
|
<Box sx={{ flex: 1 }} />
|
|
<Skeleton variant="rounded" width={90} height={36} sx={{ borderRadius: 2 }} />
|
|
</Stack>
|
|
|
|
{/* 结果区域 */}
|
|
<Skeleton variant="rounded" width="100%" height={160} sx={{ borderRadius: 3 }} />
|
|
</Box>
|
|
);
|
|
}
|
|
|
|
/**
|
|
* 页面加载骨架屏
|
|
*
|
|
* @param props - PageSkeletonProps
|
|
* @returns 骨架屏 JSX 元素
|
|
*/
|
|
export default function PageSkeleton({ variant = 'dashboard' }: PageSkeletonProps) {
|
|
if (variant === 'tool') {
|
|
return <ToolPageSkeleton />;
|
|
}
|
|
|
|
return (
|
|
<Box
|
|
sx={{
|
|
display: 'grid',
|
|
gridTemplateColumns: {
|
|
xs: '1fr',
|
|
sm: 'repeat(auto-fill, minmax(300px, 1fr))',
|
|
},
|
|
gridAutoRows: '1fr',
|
|
gap: 2,
|
|
p: 2,
|
|
}}
|
|
>
|
|
{Array.from({ length: 6 }).map((_, index) => (
|
|
<DashboardCardSkeleton key={index} />
|
|
))}
|
|
</Box>
|
|
);
|
|
}
|
|
|
|
PageSkeleton.displayName = 'PageSkeleton';
|