Merge branch 'feature_2025/251117_pref' into feature_2025/251121_h5UI
* feature_2025/251117_pref: (159 commits) feat: UI调整 feat: 将滚动事件移东到组件内部 feat: 去掉背景组件 feat: 拆分左侧栏、中间聊天区、右侧栏组件, Hooks 提取 feat: 简化主组件 index.js - 使用组件组合方式重构 feat: 创建 ChatArea 组件(含 MessageRenderer、ExecutionStepsDisplay 子组件) feat:拆分工具函数 feat: 拆分BackgroundEffects 背景渐变装饰层 feat: RightSidebar (~420 行) - 模型/工具/统计 Tab 面板(单文件) feat: LeftSidebar (~280 行) - 对话历史列表 + 用户信息卡片 feat: 修复bug pref:移除黑夜模式 feat: 修复警告 feat: 提取常量配置 feat: 修复ts报错 feat: StockChartModal.tsx 替换 KLine 实现 update pay function update pay function update pay function update pay function ...
This commit is contained in:
@@ -54,13 +54,11 @@ import { WatchlistMenu, FollowingEventsMenu } from './components/FeatureMenus';
|
||||
import { useWatchlist } from '../../hooks/useWatchlist';
|
||||
import { useFollowingEvents } from '../../hooks/useFollowingEvents';
|
||||
|
||||
// Phase 7 优化: 提取的二级导航、资料完整性、右侧功能区组件
|
||||
import SecondaryNav from './components/SecondaryNav';
|
||||
// Phase 7 优化: 提取的资料完整性、右侧功能区组件
|
||||
import ProfileCompletenessAlert from './components/ProfileCompletenessAlert';
|
||||
import { useProfileCompleteness } from '../../hooks/useProfileCompleteness';
|
||||
import NavbarActions from './components/NavbarActions';
|
||||
|
||||
// Phase 7: SecondaryNav 组件已提取到 ./components/SecondaryNav/index.js
|
||||
// Phase 4: MoreNavMenu 和 NavItems 组件已提取到 Navigation 目录
|
||||
|
||||
export default function HomeNavbar() {
|
||||
@@ -152,8 +150,10 @@ export default function HomeNavbar() {
|
||||
)}
|
||||
|
||||
<Box
|
||||
position="sticky"
|
||||
position="fixed"
|
||||
top={showCompletenessAlert ? "60px" : 0}
|
||||
left={0}
|
||||
right={0}
|
||||
zIndex={1000}
|
||||
bg={navbarBg}
|
||||
backdropFilter="blur(10px)"
|
||||
@@ -199,9 +199,6 @@ export default function HomeNavbar() {
|
||||
/>
|
||||
</Box>
|
||||
|
||||
{/* 二级导航栏 - 显示当前页面所属的二级菜单 */}
|
||||
{!isMobile && <SecondaryNav showCompletenessAlert={showCompletenessAlert} />}
|
||||
|
||||
{/* 投资日历 Modal - 已移至 CalendarButton 组件内部 */}
|
||||
</>
|
||||
);
|
||||
|
||||
@@ -41,9 +41,6 @@ const NavbarActions = memo(({
|
||||
}) => {
|
||||
return (
|
||||
<HStack spacing={{ base: 2, md: 4 }}>
|
||||
{/* 主题切换按钮 */}
|
||||
<ThemeToggleButton />
|
||||
|
||||
{/* 显示加载状态 */}
|
||||
{isLoading ? (
|
||||
<Spinner size="sm" color="blue.500" />
|
||||
|
||||
@@ -1,144 +0,0 @@
|
||||
// src/components/Navbars/components/SecondaryNav/config.js
|
||||
// 二级导航配置数据
|
||||
|
||||
/**
|
||||
* 二级导航配置结构
|
||||
* - key: 匹配的路径前缀
|
||||
* - title: 导航组标题
|
||||
* - items: 导航项列表
|
||||
* - path: 路径
|
||||
* - label: 显示文本
|
||||
* - badges: 徽章列表 (可选)
|
||||
* - external: 是否外部链接 (可选)
|
||||
*/
|
||||
export const secondaryNavConfig = {
|
||||
'/community': {
|
||||
title: '高频跟踪',
|
||||
items: [
|
||||
{
|
||||
path: '/community',
|
||||
label: '事件中心',
|
||||
badges: [
|
||||
{ text: 'HOT', colorScheme: 'green' },
|
||||
{ text: 'NEW', colorScheme: 'red' }
|
||||
]
|
||||
},
|
||||
{
|
||||
path: '/concepts',
|
||||
label: '概念中心',
|
||||
badges: [{ text: 'NEW', colorScheme: 'red' }]
|
||||
},
|
||||
{
|
||||
path: '/data-browser',
|
||||
label: '数据浏览器',
|
||||
badges: [{ text: 'NEW', colorScheme: 'red' }]
|
||||
}
|
||||
]
|
||||
},
|
||||
'/concepts': {
|
||||
title: '高频跟踪',
|
||||
items: [
|
||||
{
|
||||
path: '/community',
|
||||
label: '事件中心',
|
||||
badges: [
|
||||
{ text: 'HOT', colorScheme: 'green' },
|
||||
{ text: 'NEW', colorScheme: 'red' }
|
||||
]
|
||||
},
|
||||
{
|
||||
path: '/concepts',
|
||||
label: '概念中心',
|
||||
badges: [{ text: 'NEW', colorScheme: 'red' }]
|
||||
},
|
||||
{
|
||||
path: '/data-browser',
|
||||
label: '数据浏览器',
|
||||
badges: [{ text: 'NEW', colorScheme: 'red' }]
|
||||
}
|
||||
]
|
||||
},
|
||||
'/data-browser': {
|
||||
title: '高频跟踪',
|
||||
items: [
|
||||
{
|
||||
path: '/community',
|
||||
label: '事件中心',
|
||||
badges: [
|
||||
{ text: 'HOT', colorScheme: 'green' },
|
||||
{ text: 'NEW', colorScheme: 'red' }
|
||||
]
|
||||
},
|
||||
{
|
||||
path: '/concepts',
|
||||
label: '概念中心',
|
||||
badges: [{ text: 'NEW', colorScheme: 'red' }]
|
||||
},
|
||||
{
|
||||
path: '/data-browser',
|
||||
label: '数据浏览器',
|
||||
badges: [{ text: 'NEW', colorScheme: 'red' }]
|
||||
}
|
||||
]
|
||||
},
|
||||
'/limit-analyse': {
|
||||
title: '行情复盘',
|
||||
items: [
|
||||
{
|
||||
path: '/limit-analyse',
|
||||
label: '涨停分析',
|
||||
badges: [{ text: 'FREE', colorScheme: 'blue' }]
|
||||
},
|
||||
{
|
||||
path: '/stocks',
|
||||
label: '个股中心',
|
||||
badges: [{ text: 'HOT', colorScheme: 'green' }]
|
||||
},
|
||||
{
|
||||
path: '/trading-simulation',
|
||||
label: '模拟盘',
|
||||
badges: [{ text: 'NEW', colorScheme: 'red' }]
|
||||
}
|
||||
]
|
||||
},
|
||||
'/stocks': {
|
||||
title: '行情复盘',
|
||||
items: [
|
||||
{
|
||||
path: '/limit-analyse',
|
||||
label: '涨停分析',
|
||||
badges: [{ text: 'FREE', colorScheme: 'blue' }]
|
||||
},
|
||||
{
|
||||
path: '/stocks',
|
||||
label: '个股中心',
|
||||
badges: [{ text: 'HOT', colorScheme: 'green' }]
|
||||
},
|
||||
{
|
||||
path: '/trading-simulation',
|
||||
label: '模拟盘',
|
||||
badges: [{ text: 'NEW', colorScheme: 'red' }]
|
||||
}
|
||||
]
|
||||
},
|
||||
'/trading-simulation': {
|
||||
title: '行情复盘',
|
||||
items: [
|
||||
{
|
||||
path: '/limit-analyse',
|
||||
label: '涨停分析',
|
||||
badges: [{ text: 'FREE', colorScheme: 'blue' }]
|
||||
},
|
||||
{
|
||||
path: '/stocks',
|
||||
label: '个股中心',
|
||||
badges: [{ text: 'HOT', colorScheme: 'green' }]
|
||||
},
|
||||
{
|
||||
path: '/trading-simulation',
|
||||
label: '模拟盘',
|
||||
badges: [{ text: 'NEW', colorScheme: 'red' }]
|
||||
}
|
||||
]
|
||||
}
|
||||
};
|
||||
@@ -1,138 +0,0 @@
|
||||
// src/components/Navbars/components/SecondaryNav/index.js
|
||||
// 二级导航栏组件 - 显示当前一级菜单下的所有二级菜单项
|
||||
|
||||
import React, { memo } from 'react';
|
||||
import {
|
||||
Box,
|
||||
Container,
|
||||
HStack,
|
||||
Text,
|
||||
Button,
|
||||
Flex,
|
||||
Badge,
|
||||
useColorModeValue
|
||||
} from '@chakra-ui/react';
|
||||
import { useNavigate, useLocation } from 'react-router-dom';
|
||||
import { useNavigationEvents } from '../../../../hooks/useNavigationEvents';
|
||||
import { secondaryNavConfig } from './config';
|
||||
|
||||
/**
|
||||
* 二级导航栏组件
|
||||
* 根据当前路径显示对应的二级菜单项
|
||||
*
|
||||
* @param {Object} props
|
||||
* @param {boolean} props.showCompletenessAlert - 是否显示完整性提醒(影响 sticky top 位置)
|
||||
*/
|
||||
const SecondaryNav = memo(({ showCompletenessAlert }) => {
|
||||
const navigate = useNavigate();
|
||||
const location = useLocation();
|
||||
|
||||
// 颜色模式
|
||||
const navbarBg = useColorModeValue('gray.50', 'gray.700');
|
||||
const itemHoverBg = useColorModeValue('white', 'gray.600');
|
||||
const borderColorValue = useColorModeValue('gray.200', 'gray.600');
|
||||
|
||||
// 导航埋点
|
||||
const navEvents = useNavigationEvents({ component: 'secondary_nav' });
|
||||
|
||||
// 找到当前路径对应的二级导航配置
|
||||
const currentConfig = Object.keys(secondaryNavConfig).find(key =>
|
||||
location.pathname.includes(key)
|
||||
);
|
||||
|
||||
// 如果没有匹配的二级导航,不显示
|
||||
if (!currentConfig) return null;
|
||||
|
||||
const config = secondaryNavConfig[currentConfig];
|
||||
|
||||
return (
|
||||
<Box
|
||||
bg={navbarBg}
|
||||
borderBottom="1px"
|
||||
borderColor={borderColorValue}
|
||||
py={2}
|
||||
position="sticky"
|
||||
top={showCompletenessAlert ? "120px" : "60px"}
|
||||
zIndex={100}
|
||||
>
|
||||
<Container maxW="container.xl" px={4}>
|
||||
<HStack spacing={1}>
|
||||
{/* 显示一级菜单标题 */}
|
||||
<Text fontSize="sm" color="gray.500" mr={2}>
|
||||
{config.title}:
|
||||
</Text>
|
||||
|
||||
{/* 二级菜单项 */}
|
||||
{config.items.map((item, index) => {
|
||||
const isActive = location.pathname.includes(item.path);
|
||||
|
||||
return item.external ? (
|
||||
<Button
|
||||
key={index}
|
||||
as="a"
|
||||
href={item.path}
|
||||
size="sm"
|
||||
variant="ghost"
|
||||
bg="transparent"
|
||||
color="inherit"
|
||||
fontWeight="normal"
|
||||
_hover={{ bg: itemHoverBg }}
|
||||
borderRadius="md"
|
||||
px={3}
|
||||
>
|
||||
<Flex align="center" gap={2}>
|
||||
<Text>{item.label}</Text>
|
||||
{item.badges && item.badges.length > 0 && (
|
||||
<HStack spacing={1}>
|
||||
{item.badges.map((badge, bIndex) => (
|
||||
<Badge key={bIndex} size="xs" colorScheme={badge.colorScheme}>
|
||||
{badge.text}
|
||||
</Badge>
|
||||
))}
|
||||
</HStack>
|
||||
)}
|
||||
</Flex>
|
||||
</Button>
|
||||
) : (
|
||||
<Button
|
||||
key={index}
|
||||
onClick={() => {
|
||||
// 追踪侧边栏菜单点击
|
||||
navEvents.trackSidebarMenuClicked(item.label, item.path, 2, false);
|
||||
navigate(item.path);
|
||||
}}
|
||||
size="sm"
|
||||
variant="ghost"
|
||||
bg={isActive ? 'blue.50' : 'transparent'}
|
||||
color={isActive ? 'blue.600' : 'inherit'}
|
||||
fontWeight={isActive ? 'bold' : 'normal'}
|
||||
borderBottom={isActive ? '2px solid' : 'none'}
|
||||
borderColor="blue.600"
|
||||
borderRadius={isActive ? '0' : 'md'}
|
||||
_hover={{ bg: isActive ? 'blue.100' : itemHoverBg }}
|
||||
px={3}
|
||||
>
|
||||
<Flex align="center" gap={2}>
|
||||
<Text>{item.label}</Text>
|
||||
{item.badges && item.badges.length > 0 && (
|
||||
<HStack spacing={1}>
|
||||
{item.badges.map((badge, bIndex) => (
|
||||
<Badge key={bIndex} size="xs" colorScheme={badge.colorScheme}>
|
||||
{badge.text}
|
||||
</Badge>
|
||||
))}
|
||||
</HStack>
|
||||
)}
|
||||
</Flex>
|
||||
</Button>
|
||||
);
|
||||
})}
|
||||
</HStack>
|
||||
</Container>
|
||||
</Box>
|
||||
);
|
||||
});
|
||||
|
||||
SecondaryNav.displayName = 'SecondaryNav';
|
||||
|
||||
export default SecondaryNav;
|
||||
@@ -1,51 +0,0 @@
|
||||
// src/components/Navbars/components/ThemeToggleButton.js
|
||||
// 主题切换按钮组件 - Phase 7 优化:添加导航埋点支持
|
||||
|
||||
import React, { memo } from 'react';
|
||||
import { IconButton, useColorMode } from '@chakra-ui/react';
|
||||
import { SunIcon, MoonIcon } from '@chakra-ui/icons';
|
||||
import { useNavigationEvents } from '../../../hooks/useNavigationEvents';
|
||||
|
||||
/**
|
||||
* 主题切换按钮组件
|
||||
* 支持在亮色和暗色主题之间切换,包含导航埋点
|
||||
*
|
||||
* 性能优化:
|
||||
* - 使用 memo 避免父组件重新渲染时的不必要更新
|
||||
* - 只依赖 colorMode,当主题切换时才重新渲染
|
||||
*
|
||||
* @param {Object} props
|
||||
* @param {string} props.size - 按钮大小,默认 'sm'
|
||||
* @param {string} props.variant - 按钮样式,默认 'ghost'
|
||||
* @returns {JSX.Element}
|
||||
*/
|
||||
const ThemeToggleButton = memo(({ size = 'sm', variant = 'ghost' }) => {
|
||||
const { colorMode, toggleColorMode } = useColorMode();
|
||||
const navEvents = useNavigationEvents({ component: 'theme_toggle' });
|
||||
|
||||
const handleToggle = () => {
|
||||
// 追踪主题切换
|
||||
const fromTheme = colorMode;
|
||||
const toTheme = colorMode === 'light' ? 'dark' : 'light';
|
||||
navEvents.trackThemeChanged(fromTheme, toTheme);
|
||||
|
||||
// 切换主题
|
||||
toggleColorMode();
|
||||
};
|
||||
|
||||
return (
|
||||
<IconButton
|
||||
aria-label="切换主题"
|
||||
icon={colorMode === 'light' ? <MoonIcon /> : <SunIcon />}
|
||||
onClick={handleToggle}
|
||||
variant={variant}
|
||||
size={size}
|
||||
minW={{ base: '36px', md: '40px' }}
|
||||
minH={{ base: '36px', md: '40px' }}
|
||||
/>
|
||||
);
|
||||
});
|
||||
|
||||
ThemeToggleButton.displayName = 'ThemeToggleButton';
|
||||
|
||||
export default ThemeToggleButton;
|
||||
Reference in New Issue
Block a user