feat: 更新骨架屏UI

This commit is contained in:
zdl
2025-11-24 19:26:44 +08:00
parent db86386e85
commit d93ce0104b

View File

@@ -1,8 +1,13 @@
/** /**
* 首页骨架屏组件 * 首页骨架屏组件
* 模拟首页的 6 个功能卡片布局,减少白屏感知时间 * 精准模拟首页的深色科技风格布局,减少白屏感知时间
* *
* 使用 Chakra UI 的 Skeleton 组件 * 关键特性:
* - ✅ 深色渐变背景(与实际页面一致)
* - ✅ 玻璃态透明卡片
* - ✅ 全屏 Hero 区域布局
* - ✅ Featured 卡片横向布局 + 黄色边框
* - ✅ 5 个常规卡片网格布局
* *
* @module views/Home/components/HomePageSkeleton * @module views/Home/components/HomePageSkeleton
*/ */
@@ -16,7 +21,7 @@ import {
SkeletonText, SkeletonText,
VStack, VStack,
HStack, HStack,
useColorModeValue, Flex,
} from '@chakra-ui/react'; } from '@chakra-ui/react';
// ============================================================ // ============================================================
@@ -31,66 +36,176 @@ interface HomePageSkeletonProps {
} }
// ============================================================ // ============================================================
// 单个卡片骨架 // Featured 卡片骨架(横向布局)
// ============================================================ // ============================================================
const FeatureCardSkeleton: React.FC<{ isFeatured?: boolean }> = ({ isFeatured = false }) => { const FeaturedCardSkeleton: React.FC<{ speed?: number }> = ({ speed = 0.8 }) => {
const bg = useColorModeValue('white', 'gray.800');
const borderColor = useColorModeValue('gray.200', 'gray.700');
return ( return (
<Box <Box
bg={bg} bg="transparent"
borderRadius="xl" border="2px solid"
borderWidth="1px" borderColor="yellow.400"
borderColor={borderColor} borderRadius={{ base: '2xl', md: '3xl' }}
p={isFeatured ? 8 : 6} overflow="hidden"
h={isFeatured ? '350px' : '280px'}
boxShadow={isFeatured ? 'xl' : 'md'}
position="relative" position="relative"
shadow="2xl"
w="100%"
_before={{
content: '""',
position: 'absolute',
top: 0,
left: 0,
right: 0,
bottom: 0,
background: 'linear-gradient(135deg, rgba(255, 215, 0, 0.1) 0%, rgba(255, 165, 0, 0.05) 100%)',
zIndex: 0,
}}
> >
<VStack align="start" spacing={4} h="full"> <Box p={{ base: 6, md: 8 }} position="relative" zIndex={1}>
{/* 图标骨架 */} {/* 横向布局 */}
<Flex
direction={{ base: 'column', md: 'row' }}
align={{ base: 'stretch', md: 'center' }}
justify={{ base: 'flex-start', md: 'space-between' }}
gap={{ base: 4, md: 6 }}
>
{/* 左侧:图标 + 标题 + 描述 */}
<Flex align="center" gap={{ base: 4, md: 6 }} flex={1}>
{/* 图标骨架 */}
<Skeleton
height={{ base: '48px', md: '56px' }}
width={{ base: '48px', md: '56px' }}
borderRadius={{ base: 'lg', md: 'xl' }}
startColor="yellow.200"
endColor="yellow.400"
speed={speed}
/>
{/* 标题 + 描述 */}
<VStack align="start" spacing={{ base: 1, md: 2 }} flex={1}>
{/* 标题 + 徽章 */}
<HStack>
<Skeleton
height={{ base: '28px', md: '32px' }}
width="150px"
borderRadius="md"
startColor="whiteAlpha.300"
endColor="whiteAlpha.500"
speed={speed}
/>
<Skeleton
height="20px"
width="50px"
borderRadius="full"
startColor="yellow.200"
endColor="yellow.400"
speed={speed}
/>
</HStack>
{/* 描述 */}
<SkeletonText
mt="2"
noOfLines={2}
spacing="3"
skeletonHeight="2"
width="100%"
maxW={{ md: 'md' }}
startColor="whiteAlpha.200"
endColor="whiteAlpha.400"
speed={speed}
/>
</VStack>
</Flex>
{/* 右侧:按钮 */}
<Skeleton
height="44px"
width={{ base: '100%', md: '140px' }}
borderRadius="full"
startColor="yellow.300"
endColor="yellow.500"
flexShrink={0}
speed={speed}
/>
</Flex>
</Box>
</Box>
);
};
// ============================================================
// 常规卡片骨架(纵向布局)
// ============================================================
const RegularCardSkeleton: React.FC<{ speed?: number }> = ({ speed = 0.8 }) => {
return (
<Box
bg="whiteAlpha.100"
backdropFilter="blur(10px)"
border="1px solid"
borderColor="whiteAlpha.200"
borderRadius={{ base: 'xl', md: '2xl' }}
p={{ base: 5, md: 6 }}
minH={{ base: 'auto', md: '180px' }}
transition="all 0.3s ease"
>
<VStack spacing={{ base: 3, md: 4 }} align="start" h="100%">
{/* 图标 + 徽章 */}
<HStack>
<Skeleton
height={{ base: '40px', md: '48px' }}
width={{ base: '40px', md: '48px' }}
borderRadius="lg"
startColor="whiteAlpha.200"
endColor="whiteAlpha.400"
speed={speed}
/>
<Skeleton
height="20px"
width="50px"
borderRadius="full"
startColor="whiteAlpha.200"
endColor="whiteAlpha.400"
speed={speed}
/>
</HStack>
{/* 标题 */}
<Skeleton <Skeleton
height={isFeatured ? '60px' : '48px'} height={{ base: '24px', md: '28px' }}
width={isFeatured ? '60px' : '48px'} width="70%"
borderRadius="lg" borderRadius="md"
startColor={isFeatured ? 'blue.100' : 'gray.100'} startColor="whiteAlpha.300"
endColor={isFeatured ? 'blue.200' : 'gray.200'} endColor="whiteAlpha.500"
speed={speed}
/> />
{/* 标题骨架 */} {/* 描述 */}
<Skeleton height="28px" width="70%" borderRadius="md" />
{/* 描述骨架 */}
<SkeletonText <SkeletonText
mt="2" mt="2"
noOfLines={isFeatured ? 4 : 3} noOfLines={2}
spacing="3" spacing="3"
skeletonHeight="2" skeletonHeight="2"
width="100%" width="100%"
startColor="whiteAlpha.200"
endColor="whiteAlpha.400"
speed={speed}
flex={1}
/> />
{/* 按钮骨架 */} {/* 按钮 */}
<Skeleton <Skeleton
height="40px" height="44px"
width={isFeatured ? '140px' : '100px'} width={{ base: '100%', md: 'auto' }}
minW={{ md: '80px' }}
borderRadius="md" borderRadius="md"
mt="auto" alignSelf={{ base: 'stretch', md: 'flex-end' }}
startColor="whiteAlpha.200"
endColor="whiteAlpha.400"
speed={speed}
/> />
</VStack> </VStack>
{/* Featured 徽章骨架 */}
{isFeatured && (
<Skeleton
position="absolute"
top="4"
right="4"
height="24px"
width="80px"
borderRadius="full"
/>
)}
</Box> </Box>
); );
}; };
@@ -103,84 +218,58 @@ export const HomePageSkeleton: React.FC<HomePageSkeletonProps> = ({
isAnimated = true, isAnimated = true,
speed = 0.8, speed = 0.8,
}) => { }) => {
const containerBg = useColorModeValue('gray.50', 'gray.900');
return ( return (
<Box <Box
w="full" w="full"
minH="100vh" minH="100vh"
bg={containerBg} bg="linear-gradient(135deg, #0E0C15 0%, #15131D 50%, #252134 100%)"
pt={{ base: '120px', md: '140px' }} overflow="hidden"
pb={{ base: '60px', md: '80px' }} position="relative"
> >
<Container maxW="container.xl"> <Container maxW="7xl" position="relative" zIndex={30} px={{ base: 10, md: 10, lg: 10 }}>
<VStack spacing={{ base: 8, md: 12 }} align="stretch"> <VStack
{/* 顶部标题区域骨架 */} spacing={{ base: 8, md: 12, lg: 16 }}
<VStack spacing={4} textAlign="center"> align="stretch"
minH="100vh"
justify="center"
>
{/* 主标题区域骨架 */}
<VStack spacing={{ base: 4, md: 5, lg: 6 }} textAlign="center" pt={{ base: 4, md: 6, lg: 8 }}>
{/* 主标题 */} {/* 主标题 */}
<Skeleton <Skeleton
height={{ base: '40px', md: '56px' }} height={{ base: '40px', md: '56px', lg: '64px' }}
width={{ base: '80%', md: '500px' }} width={{ base: '80%', md: '500px', lg: '600px' }}
borderRadius="md" borderRadius="md"
startColor="whiteAlpha.300"
endColor="whiteAlpha.500"
speed={speed} speed={speed}
/> />
{/* 副标题 */} {/* 副标题 */}
<Skeleton <Skeleton
height={{ base: '20px', md: '24px' }} height={{ base: '20px', md: '24px', lg: '28px' }}
width={{ base: '90%', md: '600px' }} width={{ base: '90%', md: '600px', lg: '700px' }}
borderRadius="md" borderRadius="md"
startColor="whiteAlpha.200"
endColor="whiteAlpha.400"
speed={speed} speed={speed}
/> />
{/* CTA 按钮 */}
<HStack spacing={4} mt={4}>
<Skeleton
height="48px"
width="140px"
borderRadius="lg"
speed={speed}
/>
<Skeleton
height="48px"
width="140px"
borderRadius="lg"
speed={speed}
/>
</HStack>
</VStack> </VStack>
{/* 功能卡片网格骨架 */} {/* 核心功能面板 */}
<SimpleGrid <Box pb={{ base: 8, md: 12 }}>
columns={{ base: 1, md: 2, lg: 3 }} <VStack spacing={{ base: 6, md: 8 }}>
spacing={{ base: 6, md: 8 }} {/* Featured 卡片 - 新闻中心(横向布局) */}
mt={8} <FeaturedCardSkeleton speed={speed} />
>
{/* 第一张卡片 - Featured (新闻中心) */}
<Box gridColumn={{ base: 'span 1', lg: 'span 2' }}>
<FeatureCardSkeleton isFeatured />
</Box>
{/* 其 5 卡片 */} {/* 其 5 个功能卡片 */}
{[1, 2, 3, 4, 5].map((index) => ( <SimpleGrid columns={{ base: 1, md: 2, lg: 3 }} spacing={{ base: 4, md: 5, lg: 6 }} w="100%">
<FeatureCardSkeleton key={index} /> {[1, 2, 3, 4, 5].map((index) => (
))} <RegularCardSkeleton key={index} speed={speed} />
</SimpleGrid> ))}
</SimpleGrid>
{/* 底部装饰元素骨架 */} </VStack>
<HStack justify="center" spacing={8} mt={12}> </Box>
{[1, 2, 3].map((index) => (
<VStack key={index} spacing={2} align="center">
<Skeleton
height="40px"
width="40px"
borderRadius="full"
speed={speed}
/>
<Skeleton height="16px" width="60px" borderRadius="md" speed={speed} />
</VStack>
))}
</HStack>
</VStack> </VStack>
</Container> </Container>
</Box> </Box>