feat: homets 化 创建类型定义文件

创建常量配置文件
 创建自定义 Hook

 创建组件目录
创建 HeroHeader 组件
创建 FeaturedFeatureCard 组件
创建 FeatureCard 组件
创建新的 HomePage.tsx
This commit is contained in:
zdl
2025-11-25 14:44:46 +08:00
parent c771f7cae6
commit 03f1331202
9 changed files with 640 additions and 379 deletions

View File

@@ -0,0 +1,66 @@
// src/constants/homeFeatures.ts
// 首页功能特性配置
import type { Feature } from '@/types/home';
/**
* 核心功能特性列表
* 第一个功能为特色功能,会以突出样式显示
*/
export const CORE_FEATURES: Feature[] = [
{
id: 'news-catalyst',
title: '新闻中心',
description: '实时新闻事件分析,捕捉市场催化因子',
icon: '📊',
color: 'yellow',
url: '/community',
badge: '核心',
featured: true
},
{
id: 'concepts',
title: '概念中心',
description: '热门概念与主题投资分析追踪',
icon: '🎯',
color: 'purple',
url: '/concepts',
badge: '热门'
},
{
id: 'stocks',
title: '个股信息汇总',
description: '全面的个股基本面信息整合',
icon: '📈',
color: 'blue',
url: '/stocks',
badge: '全面'
},
{
id: 'limit-analyse',
title: '涨停板块分析',
description: '涨停板数据深度分析与规律挖掘',
icon: '🚀',
color: 'green',
url: '/limit-analyse',
badge: '精准'
},
{
id: 'company',
title: '个股罗盘',
description: '个股全方位分析与投资决策支持',
icon: '🧭',
color: 'orange',
url: '/company?scode=688256',
badge: '专业'
},
{
id: 'trading-simulation',
title: '模拟盘交易',
description: '100万起始资金,体验真实交易环境',
icon: '💰',
color: 'teal',
url: '/trading-simulation',
badge: '实战'
}
];

View File

@@ -0,0 +1,57 @@
// src/hooks/useHomeResponsive.ts
// 首页响应式配置 Hook
import { useBreakpointValue } from '@chakra-ui/react';
import type { ResponsiveConfig } from '@/types/home';
/**
* 首页响应式配置 Hook
* 集中管理所有响应式断点值
*
* @returns 响应式配置对象
*/
export const useHomeResponsive = (): ResponsiveConfig => {
const heroHeight = useBreakpointValue({
base: '60vh',
md: '80vh',
lg: '100vh'
});
const headingSize = useBreakpointValue({
base: 'xl',
md: '3xl',
lg: '4xl'
});
const headingLetterSpacing = useBreakpointValue({
base: '-1px',
md: '-1.5px',
lg: '-2px'
});
const heroTextSize = useBreakpointValue({
base: 'md',
md: 'lg',
lg: 'xl'
});
const containerPx = useBreakpointValue({
base: 10,
md: 10,
lg: 10
});
const showDecorations = useBreakpointValue({
base: false,
md: true
});
return {
heroHeight,
headingSize,
headingLetterSpacing,
heroTextSize,
containerPx,
showDecorations
};
};

33
src/types/home.ts Normal file
View File

@@ -0,0 +1,33 @@
// src/types/home.ts
// HomePage 相关类型定义
/**
* 功能特性配置
*/
export interface Feature {
id: string;
title: string;
description: string;
icon: string;
color: string;
url: string;
badge: string;
featured?: boolean;
}
/**
* 响应式配置
*/
export interface ResponsiveConfig {
heroHeight: string | undefined;
headingSize: string | undefined;
headingLetterSpacing: string | undefined;
heroTextSize: string | undefined;
containerPx: number | undefined;
showDecorations: boolean | undefined;
}
/**
* 功能卡片点击处理函数类型
*/
export type FeatureClickHandler = (feature: Feature) => void;

View File

@@ -1,379 +0,0 @@
// src/views/Home/HomePage.js - 专业投资分析平台
import React, { useEffect, useCallback } from 'react';
import {
Box,
Container,
Heading,
Text,
Card,
CardBody,
Badge,
Button,
Flex,
VStack,
HStack,
SimpleGrid,
useBreakpointValue
} from '@chakra-ui/react';
import { useAuth } from '../../contexts/AuthContext';
import { useNavigate } from 'react-router-dom';
import heroBg from '../../assets/img/BackgroundCard1.png';
import '../../styles/home-animations.css';
import { logger } from '../../utils/logger';
import { usePostHogTrack } from '../../hooks/usePostHogRedux';
import { ACQUISITION_EVENTS } from '../../lib/constants';
export default function HomePage() {
const { user, isAuthenticated } = useAuth(); // ⚡ 移除 isLoading不再依赖它
const navigate = useNavigate();
const { track } = usePostHogTrack(); // PostHog 追踪
const [imageLoaded, setImageLoaded] = React.useState(false);
// 响应式配置
const heroHeight = useBreakpointValue({ base: '60vh', md: '80vh', lg: '100vh' });
const headingSize = useBreakpointValue({ base: 'xl', md: '3xl', lg: '4xl' });
const headingLetterSpacing = useBreakpointValue({ base: '-1px', md: '-1.5px', lg: '-2px' });
const heroTextSize = useBreakpointValue({ base: 'md', md: 'lg', lg: 'xl' });
const containerPx = useBreakpointValue({ base: 10, md: 10, lg: 10 });
const showDecorations = useBreakpointValue({ base: false, md: true });
// 保留原有的调试信息
useEffect(() => {
logger.debug('HomePage', 'AuthContext状态', {
userId: user?.id,
username: user?.username,
nickname: user?.nickname,
isAuthenticated,
hasUser: !!user
});
}, [user?.id, isAuthenticated]); // 只依赖 user.id,避免无限循环
// 🎯 PostHog 追踪:页面浏览
useEffect(() => {
track(ACQUISITION_EVENTS.LANDING_PAGE_VIEWED, {
timestamp: new Date().toISOString(),
is_authenticated: isAuthenticated,
user_id: user?.id || null,
});
}, [track, isAuthenticated, user?.id]);
// 核心功能配置 - 5个主要功能
const coreFeatures = [
{
id: 'news-catalyst',
title: '新闻中心',
description: '实时新闻事件分析,捕捉市场催化因子',
icon: '📊',
color: 'yellow',
url: '/community',
badge: '核心',
featured: true
},
{
id: 'concepts',
title: '概念中心',
description: '热门概念与主题投资分析追踪',
icon: '🎯',
color: 'purple',
url: '/concepts',
badge: '热门'
},
{
id: 'stocks',
title: '个股信息汇总',
description: '全面的个股基本面信息整合',
icon: '📈',
color: 'blue',
url: '/stocks',
badge: '全面'
},
{
id: 'limit-analyse',
title: '涨停板块分析',
description: '涨停板数据深度分析与规律挖掘',
icon: '🚀',
color: 'green',
url: '/limit-analyse',
badge: '精准'
},
{
id: 'company',
title: '个股罗盘',
description: '个股全方位分析与投资决策支持',
icon: '🧭',
color: 'orange',
url: '/company?scode=688256',
badge: '专业'
},
{
id: 'trading-simulation',
title: '模拟盘交易',
description: '100万起始资金体验真实交易环境',
icon: '💰',
color: 'teal',
url: '/trading-simulation',
badge: '实战'
}
];
// @TODO 如何区分内部链接和外部链接?
const handleProductClick = useCallback((feature) => {
// 🎯 PostHog 追踪:功能卡片点击
track(ACQUISITION_EVENTS.FEATURE_CARD_CLICKED, {
feature_id: feature.id,
feature_title: feature.title,
feature_url: feature.url,
is_featured: feature.featured || false,
link_type: feature.url.startsWith('http') ? 'external' : 'internal',
});
// 原有导航逻辑
if (feature.url.startsWith('http')) {
// 外部链接,直接打开
window.open(feature.url, '_blank');
} else {
// 内部路由
navigate(feature.url);
}
}, [track, navigate]);
return (
<Box>
{/* Hero Section - 深色科技风格 */}
<Box
position="relative"
minH={heroHeight}
bg="linear-gradient(135deg, #0E0C15 0%, #15131D 50%, #252134 100%)"
overflow="hidden"
>
{/* 背景图片和装饰 - 优化:延迟加载 */}
<Box
position="absolute"
top="0"
right="0"
w="50%"
h="100%"
bgImage={imageLoaded ? `url(${heroBg})` : 'none'}
bgSize="cover"
bgPosition="center"
opacity={imageLoaded ? 0.3 : 0}
transition="opacity 0.5s ease-in"
_after={{
content: '""',
position: 'absolute',
top: 0,
left: 0,
right: 0,
bottom: 0,
background: 'linear-gradient(90deg, rgba(14, 12, 21, 0.9) 0%, rgba(14, 12, 21, 0.3) 100%)'
}}
/>
{/* 预加载背景图片 */}
<Box display="none">
<img
src={heroBg}
alt=""
onLoad={() => setImageLoaded(true)}
onError={() => setImageLoaded(true)}
/>
</Box>
{/* 装饰性几何图形 - 移动端隐藏 */}
{showDecorations && (
<>
<Box
position="absolute"
top="20%"
left="10%"
w={{ base: '100px', md: '150px', lg: '200px' }}
h={{ base: '100px', md: '150px', lg: '200px' }}
borderRadius="50%"
bg="rgba(255, 215, 0, 0.1)"
filter="blur(80px)"
className="float-animation"
/>
<Box
position="absolute"
bottom="30%"
right="20%"
w={{ base: '80px', md: '120px', lg: '150px' }}
h={{ base: '80px', md: '120px', lg: '150px' }}
borderRadius="50%"
bg="rgba(138, 43, 226, 0.1)"
filter="blur(60px)"
className="float-animation-reverse"
/>
</>
)}
<Container maxW="7xl" position="relative" zIndex={30} px={containerPx}>
<VStack spacing={{ base: 8, md: 12, lg: 16 }} align="stretch" minH={heroHeight} justify="center">
{/* 主标题区域 */}
<VStack spacing={{ base: 4, md: 5, lg: 6 }} textAlign="center" pt={{ base: 4, md: 6, lg: 8 }}>
<Heading
size={headingSize}
color="white"
fontWeight="900"
letterSpacing={headingLetterSpacing}
lineHeight="shorter"
>
智能投资分析平台
</Heading>
<Text fontSize={heroTextSize} color="whiteAlpha.800" maxW={{ base: '100%', md: '2xl', lg: '3xl' }} lineHeight="tall" px={{ base: 4, md: 0 }}>
专业投资研究工具助您把握市场机遇
</Text>
</VStack>
{/* 核心功能面板 */}
<Box pb={{ base: 8, md: 12 }}>
<VStack spacing={{ base: 6, md: 8 }}>
{/* 新闻中心 - 突出显示 */}
<Card
bg="transparent"
border="2px solid"
borderColor="yellow.400"
borderRadius={{ base: '2xl', md: '3xl' }}
overflow="hidden"
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
}}
>
<CardBody 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}>
<Box
p={{ base: 3, md: 4 }}
borderRadius={{ base: 'lg', md: 'xl' }}
bg="yellow.400"
color="black"
>
<Text fontSize={{ base: '2xl', md: '3xl' }}>{coreFeatures[0].icon}</Text>
</Box>
<VStack align="start" spacing={{ base: 1, md: 2 }} flex={1}>
<HStack>
<Heading size={{ base: 'lg', md: 'xl' }} color="white">
{coreFeatures[0].title}
</Heading>
<Badge colorScheme="yellow" variant="solid" fontSize={{ base: 'xs', md: 'sm' }}>
{coreFeatures[0].badge}
</Badge>
</HStack>
<Text color="whiteAlpha.800" fontSize={{ base: 'md', md: 'lg' }} maxW={{ md: 'md' }} lineHeight="tall">
{coreFeatures[0].description}
</Text>
</VStack>
</Flex>
<Button
colorScheme="yellow"
size={{ base: 'md', md: 'lg' }}
borderRadius="full"
fontWeight="bold"
w={{ base: '100%', md: 'auto' }}
onClick={() => handleProductClick(coreFeatures[0])}
minH="44px"
flexShrink={0}
>
进入功能
</Button>
</Flex>
</CardBody>
</Card>
{/* 其他5个功能 */}
<SimpleGrid columns={{ base: 1, md: 2, lg: 3 }} spacing={{ base: 4, md: 5, lg: 6 }} w="100%">
{coreFeatures.slice(1).map((feature) => (
<Card
key={feature.id}
bg="whiteAlpha.100"
backdropFilter="blur(10px)"
border="1px solid"
borderColor="whiteAlpha.200"
borderRadius={{ base: 'xl', md: '2xl' }}
transition="all 0.3s ease"
_hover={{
bg: 'whiteAlpha.200',
borderColor: `${feature.color}.400`,
transform: 'translateY(-4px)',
shadow: '2xl'
}}
_active={{
bg: 'whiteAlpha.200',
borderColor: `${feature.color}.400`,
transform: 'translateY(-2px)'
}}
onClick={() => handleProductClick(feature)}
minH={{ base: 'auto', md: '180px' }}
>
<CardBody p={{ base: 5, md: 6 }}>
<VStack spacing={{ base: 3, md: 4 }} align="start" h="100%">
<HStack>
<Box
p={{ base: 2, md: 3 }}
borderRadius="lg"
bg={`${feature.color}.50`}
border="1px solid"
borderColor={`${feature.color}.200`}
>
<Text fontSize={{ base: 'xl', md: '2xl' }}>{feature.icon}</Text>
</Box>
<Badge colorScheme={feature.color} variant="solid" fontSize={{ base: 'xs', md: 'sm' }}>
{feature.badge}
</Badge>
</HStack>
<VStack align="start" spacing={{ base: 1, md: 2 }} flex={1}>
<Heading size={{ base: 'md', md: 'lg' }} color="white">
{feature.title}
</Heading>
<Text color="whiteAlpha.800" fontSize={{ base: 'xs', md: 'sm' }} lineHeight="tall">
{feature.description}
</Text>
</VStack>
<Button
colorScheme={feature.color}
size={{ base: 'md', md: 'sm' }}
variant="outline"
alignSelf="flex-end"
w={{ base: '100%', md: 'auto' }}
minH="44px"
onClick={(e) => {
e.stopPropagation();
handleProductClick(feature);
}}
>
使用
</Button>
</VStack>
</CardBody>
</Card>
))}
</SimpleGrid>
</VStack>
</Box>
</VStack>
</Container>
</Box>
</Box>
);
}

139
src/views/Home/HomePage.tsx Normal file
View File

@@ -0,0 +1,139 @@
// src/views/Home/HomePage.tsx
// 首页 - 专业投资分析平台
import React, { useEffect, useCallback, useState } from 'react';
import { Box, Container, VStack, SimpleGrid } from '@chakra-ui/react';
import { useNavigate } from 'react-router-dom';
import { useAuth } from '@/contexts/AuthContext';
import { usePostHogTrack } from '@/hooks/usePostHogRedux';
import { useHomeResponsive } from '@/hooks/useHomeResponsive';
import { ACQUISITION_EVENTS } from '@/lib/constants';
import { CORE_FEATURES } from '@/constants/homeFeatures';
import type { Feature } from '@/types/home';
import { HeroBackground } from './components/HeroBackground';
import { HeroHeader } from './components/HeroHeader';
import { FeaturedFeatureCard } from './components/FeaturedFeatureCard';
import { FeatureCard } from './components/FeatureCard';
import '@/styles/home-animations.css';
/**
* 首页组件
* 展示平台核心功能,引导用户探索各个功能模块
*/
const HomePage: React.FC = () => {
const { user, isAuthenticated } = useAuth();
const navigate = useNavigate();
const { track } = usePostHogTrack();
const [imageLoaded, setImageLoaded] = useState(false);
// 响应式配置
const {
heroHeight,
headingSize,
headingLetterSpacing,
heroTextSize,
containerPx,
showDecorations
} = useHomeResponsive();
// PostHog 追踪:页面浏览
useEffect(() => {
track(ACQUISITION_EVENTS.LANDING_PAGE_VIEWED, {
timestamp: new Date().toISOString(),
is_authenticated: isAuthenticated,
user_id: user?.id || null,
});
}, [track, isAuthenticated, user?.id]);
// 功能卡片点击处理
const handleFeatureClick = useCallback((feature: Feature) => {
// PostHog 追踪:功能卡片点击
track(ACQUISITION_EVENTS.FEATURE_CARD_VIEWED, {
feature_id: feature.id,
feature_title: feature.title,
feature_url: feature.url,
is_featured: feature.featured || false,
link_type: feature.url.startsWith('http') ? 'external' : 'internal',
});
// 导航处理
if (feature.url.startsWith('http')) {
window.open(feature.url, '_blank');
} else {
navigate(feature.url);
}
}, [track, navigate]);
// 背景图片加载完成回调
const handleImageLoad = useCallback(() => {
setImageLoaded(true);
}, []);
// 特色功能(第一个)
const featuredFeature = CORE_FEATURES[0];
// 其他功能
const regularFeatures = CORE_FEATURES.slice(1);
return (
<Box>
{/* Hero Section - 深色科技风格 */}
<Box
position="relative"
minH={heroHeight}
bg="linear-gradient(135deg, #0E0C15 0%, #15131D 50%, #252134 100%)"
overflow="hidden"
>
{/* 背景装饰 */}
<HeroBackground
imageLoaded={imageLoaded}
onImageLoad={handleImageLoad}
showDecorations={showDecorations}
/>
<Container maxW="7xl" position="relative" zIndex={30} px={containerPx}>
<VStack
spacing={{ base: 8, md: 12, lg: 16 }}
align="stretch"
minH={heroHeight}
justify="center"
>
{/* 主标题区域 */}
<HeroHeader
headingSize={headingSize}
headingLetterSpacing={headingLetterSpacing}
heroTextSize={heroTextSize}
/>
{/* 核心功能面板 */}
<Box pb={{ base: 8, md: 12 }}>
<VStack spacing={{ base: 6, md: 8 }}>
{/* 特色功能卡片 - 新闻中心 */}
<FeaturedFeatureCard
feature={featuredFeature}
onClick={handleFeatureClick}
/>
{/* 其他功能卡片 */}
<SimpleGrid
columns={{ base: 1, md: 2, lg: 3 }}
spacing={{ base: 4, md: 5, lg: 6 }}
w="100%"
>
{regularFeatures.map((feature) => (
<FeatureCard
key={feature.id}
feature={feature}
onClick={handleFeatureClick}
/>
))}
</SimpleGrid>
</VStack>
</Box>
</VStack>
</Container>
</Box>
</Box>
);
};
export default HomePage;

View File

@@ -0,0 +1,106 @@
// src/views/Home/components/FeatureCard.tsx
// 普通功能卡片组件
import React from 'react';
import {
Card,
CardBody,
VStack,
HStack,
Box,
Heading,
Text,
Badge,
Button
} from '@chakra-ui/react';
import type { Feature, FeatureClickHandler } from '@/types/home';
interface FeatureCardProps {
feature: Feature;
onClick: FeatureClickHandler;
}
/**
* 普通功能卡片组件
* 用于展示除特色功能外的其他功能
*/
export const FeatureCard: React.FC<FeatureCardProps> = ({
feature,
onClick
}) => {
return (
<Card
bg="whiteAlpha.100"
backdropFilter="blur(10px)"
border="1px solid"
borderColor="whiteAlpha.200"
borderRadius={{ base: 'xl', md: '2xl' }}
transition="all 0.3s ease"
_hover={{
bg: 'whiteAlpha.200',
borderColor: `${feature.color}.400`,
transform: 'translateY(-4px)',
shadow: '2xl'
}}
_active={{
bg: 'whiteAlpha.200',
borderColor: `${feature.color}.400`,
transform: 'translateY(-2px)'
}}
onClick={() => onClick(feature)}
minH={{ base: 'auto', md: '180px' }}
cursor="pointer"
>
<CardBody p={{ base: 5, md: 6 }}>
<VStack spacing={{ base: 3, md: 4 }} align="start" h="100%">
<HStack>
<Box
p={{ base: 2, md: 3 }}
borderRadius="lg"
bg={`${feature.color}.50`}
border="1px solid"
borderColor={`${feature.color}.200`}
>
<Text fontSize={{ base: 'xl', md: '2xl' }}>{feature.icon}</Text>
</Box>
<Badge
colorScheme={feature.color}
variant="solid"
fontSize={{ base: 'xs', md: 'sm' }}
>
{feature.badge}
</Badge>
</HStack>
<VStack align="start" spacing={{ base: 1, md: 2 }} flex={1}>
<Heading size={{ base: 'md', md: 'lg' }} color="white">
{feature.title}
</Heading>
<Text
color="whiteAlpha.800"
fontSize={{ base: 'xs', md: 'sm' }}
lineHeight="tall"
>
{feature.description}
</Text>
</VStack>
<Button
colorScheme={feature.color}
size={{ base: 'md', md: 'sm' }}
variant="outline"
alignSelf="flex-end"
w={{ base: '100%', md: 'auto' }}
minH="44px"
onClick={(e) => {
e.stopPropagation();
onClick(feature);
}}
>
使
</Button>
</VStack>
</CardBody>
</Card>
);
};

View File

@@ -0,0 +1,104 @@
// src/views/Home/components/FeaturedFeatureCard.tsx
// 特色功能卡片组件(新闻中心)
import React from 'react';
import {
Card,
CardBody,
Flex,
Box,
VStack,
HStack,
Heading,
Text,
Badge,
Button
} from '@chakra-ui/react';
import type { Feature, FeatureClickHandler } from '@/types/home';
interface FeaturedFeatureCardProps {
feature: Feature;
onClick: FeatureClickHandler;
}
/**
* 特色功能卡片组件
* 用于突出显示最重要的功能(如新闻中心)
*/
export const FeaturedFeatureCard: React.FC<FeaturedFeatureCardProps> = ({
feature,
onClick
}) => {
return (
<Card
bg="transparent"
border="2px solid"
borderColor="yellow.400"
borderRadius={{ base: '2xl', md: '3xl' }}
overflow="hidden"
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
}}
>
<CardBody 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}>
<Box
p={{ base: 3, md: 4 }}
borderRadius={{ base: 'lg', md: 'xl' }}
bg="yellow.400"
color="black"
>
<Text fontSize={{ base: '2xl', md: '3xl' }}>{feature.icon}</Text>
</Box>
<VStack align="start" spacing={{ base: 1, md: 2 }} flex={1}>
<HStack>
<Heading size={{ base: 'lg', md: 'xl' }} color="white">
{feature.title}
</Heading>
<Badge colorScheme="yellow" variant="solid" fontSize={{ base: 'xs', md: 'sm' }}>
{feature.badge}
</Badge>
</HStack>
<Text
color="whiteAlpha.800"
fontSize={{ base: 'md', md: 'lg' }}
maxW={{ md: 'md' }}
lineHeight="tall"
>
{feature.description}
</Text>
</VStack>
</Flex>
<Button
colorScheme="yellow"
size={{ base: 'md', md: 'lg' }}
borderRadius="full"
fontWeight="bold"
w={{ base: '100%', md: 'auto' }}
onClick={() => onClick(feature)}
minH="44px"
flexShrink={0}
>
</Button>
</Flex>
</CardBody>
</Card>
);
};

View File

@@ -0,0 +1,87 @@
// src/views/Home/components/HeroBackground.tsx
// 首页英雄区背景装饰组件
import React from 'react';
import { Box } from '@chakra-ui/react';
import heroBg from '@assets/img/BackgroundCard1.png';
interface HeroBackgroundProps {
imageLoaded: boolean;
onImageLoad: () => void;
showDecorations: boolean | undefined;
}
/**
* 首页英雄区背景组件
* 包含背景图片和装饰性几何图形
*/
export const HeroBackground: React.FC<HeroBackgroundProps> = ({
imageLoaded,
onImageLoad,
showDecorations
}) => {
return (
<>
{/* 背景图片 */}
<Box
position="absolute"
top="0"
right="0"
w="50%"
h="100%"
bgImage={imageLoaded ? `url(${heroBg})` : 'none'}
bgSize="cover"
bgPosition="center"
opacity={imageLoaded ? 0.3 : 0}
transition="opacity 0.5s ease-in"
_after={{
content: '""',
position: 'absolute',
top: 0,
left: 0,
right: 0,
bottom: 0,
background: 'linear-gradient(90deg, rgba(14, 12, 21, 0.9) 0%, rgba(14, 12, 21, 0.3) 100%)'
}}
/>
{/* 预加载背景图片 */}
<Box display="none">
<img
src={heroBg}
alt=""
onLoad={onImageLoad}
onError={onImageLoad}
/>
</Box>
{/* 装饰性几何图形 - 移动端隐藏 */}
{showDecorations && (
<>
<Box
position="absolute"
top="20%"
left="10%"
w={{ base: '100px', md: '150px', lg: '200px' }}
h={{ base: '100px', md: '150px', lg: '200px' }}
borderRadius="50%"
bg="rgba(255, 215, 0, 0.1)"
filter="blur(80px)"
className="float-animation"
/>
<Box
position="absolute"
bottom="30%"
right="20%"
w={{ base: '80px', md: '120px', lg: '150px' }}
h={{ base: '80px', md: '120px', lg: '150px' }}
borderRadius="50%"
bg="rgba(138, 43, 226, 0.1)"
filter="blur(60px)"
className="float-animation-reverse"
/>
</>
)}
</>
);
};

View File

@@ -0,0 +1,48 @@
// src/views/Home/components/HeroHeader.tsx
// 首页主标题区域组件
import React from 'react';
import { Heading, Text, VStack } from '@chakra-ui/react';
interface HeroHeaderProps {
headingSize: string | undefined;
headingLetterSpacing: string | undefined;
heroTextSize: string | undefined;
}
/**
* 首页主标题区域组件
* 包含主标题和副标题
*/
export const HeroHeader: React.FC<HeroHeaderProps> = ({
headingSize,
headingLetterSpacing,
heroTextSize
}) => {
return (
<VStack
spacing={{ base: 4, md: 5, lg: 6 }}
textAlign="center"
pt={{ base: 4, md: 6, lg: 8 }}
>
<Heading
size={headingSize}
color="white"
fontWeight="900"
letterSpacing={headingLetterSpacing}
lineHeight="shorter"
>
</Heading>
<Text
fontSize={heroTextSize}
color="whiteAlpha.800"
maxW={{ base: '100%', md: '2xl', lg: '3xl' }}
lineHeight="tall"
px={{ base: 4, md: 0 }}
>
,
</Text>
</VStack>
);
};