feat: 导航UI调整
This commit is contained in:
@@ -31,6 +31,7 @@ import {
|
|||||||
useColorMode,
|
useColorMode,
|
||||||
useColorModeValue,
|
useColorModeValue,
|
||||||
useToast,
|
useToast,
|
||||||
|
Tooltip,
|
||||||
} from '@chakra-ui/react';
|
} from '@chakra-ui/react';
|
||||||
import { ChevronDownIcon, HamburgerIcon, SunIcon, MoonIcon } from '@chakra-ui/icons';
|
import { ChevronDownIcon, HamburgerIcon, SunIcon, MoonIcon } from '@chakra-ui/icons';
|
||||||
import { FiStar, FiCalendar, FiUser, FiSettings, FiHome, FiLogOut } from 'react-icons/fi';
|
import { FiStar, FiCalendar, FiUser, FiSettings, FiHome, FiLogOut } from 'react-icons/fi';
|
||||||
@@ -42,6 +43,7 @@ import { logger } from '../../utils/logger';
|
|||||||
import { getApiBase } from '../../utils/apiConfig';
|
import { getApiBase } from '../../utils/apiConfig';
|
||||||
import SubscriptionButton from '../Subscription/SubscriptionButton';
|
import SubscriptionButton from '../Subscription/SubscriptionButton';
|
||||||
import SubscriptionModal from '../Subscription/SubscriptionModal';
|
import SubscriptionModal from '../Subscription/SubscriptionModal';
|
||||||
|
import CrownTooltip, { TooltipContent } from '../Subscription/CrownTooltip';
|
||||||
|
|
||||||
/** 二级导航栏组件 - 显示当前一级菜单下的所有二级菜单项 */
|
/** 二级导航栏组件 - 显示当前一级菜单下的所有二级菜单项 */
|
||||||
const SecondaryNav = ({ showCompletenessAlert }) => {
|
const SecondaryNav = ({ showCompletenessAlert }) => {
|
||||||
@@ -669,44 +671,46 @@ export default function HomeNavbar() {
|
|||||||
<Box
|
<Box
|
||||||
bg="linear-gradient(135deg, #667eea 0%, #764ba2 100%)"
|
bg="linear-gradient(135deg, #667eea 0%, #764ba2 100%)"
|
||||||
color="white"
|
color="white"
|
||||||
py={2}
|
py={{ base: 2, md: 2 }}
|
||||||
px={4}
|
px={{ base: 2, md: 4 }}
|
||||||
position="sticky"
|
position="sticky"
|
||||||
top={0}
|
top={0}
|
||||||
zIndex={1001}
|
zIndex={1001}
|
||||||
>
|
>
|
||||||
<Container maxW="container.xl">
|
<Container maxW="container.xl">
|
||||||
<HStack justify="space-between" align="center">
|
<HStack justify="space-between" align="center" spacing={{ base: 2, md: 4 }}>
|
||||||
<HStack spacing={3}>
|
<HStack spacing={{ base: 2, md: 3 }} flex={1} minW={0}>
|
||||||
<Icon as={FiStar} />
|
<Icon as={FiStar} display={{ base: 'none', sm: 'block' }} />
|
||||||
<VStack spacing={0} align="start">
|
<VStack spacing={0} align="start" flex={1} minW={0}>
|
||||||
<Text fontSize="sm" fontWeight="bold">
|
<Text fontSize={{ base: 'xs', md: 'sm' }} fontWeight="bold" noOfLines={1}>
|
||||||
完善资料,享受更好服务
|
完善资料,享受更好服务
|
||||||
</Text>
|
</Text>
|
||||||
<Text fontSize="xs" opacity={0.9}>
|
<Text fontSize={{ base: '2xs', md: 'xs' }} opacity={0.9} noOfLines={1}>
|
||||||
您还需要设置:{profileCompleteness.missingItems.join('、')}
|
您还需要设置:{profileCompleteness.missingItems.join('、')}
|
||||||
</Text>
|
</Text>
|
||||||
</VStack>
|
</VStack>
|
||||||
<Text fontSize="xs" bg="whiteAlpha.300" px={2} py={1} borderRadius="full">
|
<Text fontSize="2xs" bg="whiteAlpha.300" px={2} py={1} borderRadius="full" display={{ base: 'none', md: 'block' }}>
|
||||||
{profileCompleteness.completenessPercentage}% 完成
|
{profileCompleteness.completenessPercentage}% 完成
|
||||||
</Text>
|
</Text>
|
||||||
</HStack>
|
</HStack>
|
||||||
<HStack spacing={2}>
|
<HStack spacing={{ base: 1, md: 2 }}>
|
||||||
<Button
|
<Button
|
||||||
size="sm"
|
size={{ base: 'xs', md: 'sm' }}
|
||||||
colorScheme="whiteAlpha"
|
colorScheme="whiteAlpha"
|
||||||
variant="ghost"
|
variant="ghost"
|
||||||
onClick={() => navigate('/home/settings')}
|
onClick={() => navigate('/home/settings')}
|
||||||
|
minH={{ base: '32px', md: '40px' }}
|
||||||
>
|
>
|
||||||
立即完善
|
立即完善
|
||||||
</Button>
|
</Button>
|
||||||
<IconButton
|
<IconButton
|
||||||
size="sm"
|
size={{ base: 'xs', md: 'sm' }}
|
||||||
variant="ghost"
|
variant="ghost"
|
||||||
colorScheme="whiteAlpha"
|
colorScheme="whiteAlpha"
|
||||||
icon={<Text>×</Text>}
|
icon={<Text fontSize={{ base: 'xl', md: '2xl' }}>×</Text>}
|
||||||
onClick={() => setShowCompletenessAlert(false)}
|
onClick={() => setShowCompletenessAlert(false)}
|
||||||
aria-label="关闭提醒"
|
aria-label="关闭提醒"
|
||||||
|
minW={{ base: '32px', md: '40px' }}
|
||||||
/>
|
/>
|
||||||
</HStack>
|
</HStack>
|
||||||
</HStack>
|
</HStack>
|
||||||
@@ -722,20 +726,21 @@ export default function HomeNavbar() {
|
|||||||
backdropFilter="blur(10px)"
|
backdropFilter="blur(10px)"
|
||||||
borderBottom="1px"
|
borderBottom="1px"
|
||||||
borderColor={navbarBorder}
|
borderColor={navbarBorder}
|
||||||
py={3}
|
py={{ base: 2, md: 3 }}
|
||||||
>
|
>
|
||||||
<Container maxW="container.xl" px={4}>
|
<Container maxW="container.xl" px={{ base: 3, md: 4 }}>
|
||||||
<Flex justify="space-between" align="center">
|
<Flex justify="space-between" align="center">
|
||||||
{/* Logo - 价小前投研 */}
|
{/* Logo - 价小前投研 */}
|
||||||
<HStack spacing={6}>
|
<HStack spacing={{ base: 3, md: 6 }}>
|
||||||
<Text
|
<Text
|
||||||
fontSize="xl"
|
fontSize={{ base: 'lg', md: 'xl' }}
|
||||||
fontWeight="bold"
|
fontWeight="bold"
|
||||||
color={brandText}
|
color={brandText}
|
||||||
cursor="pointer"
|
cursor="pointer"
|
||||||
_hover={{ color: brandHover }}
|
_hover={{ color: brandHover }}
|
||||||
onClick={() => navigate('/home')}
|
onClick={() => navigate('/home')}
|
||||||
style={{ minWidth: '140px' }}
|
style={{ minWidth: isMobile ? '100px' : '140px' }}
|
||||||
|
noOfLines={1}
|
||||||
>
|
>
|
||||||
价小前投研
|
价小前投研
|
||||||
</Text>
|
</Text>
|
||||||
@@ -752,13 +757,15 @@ export default function HomeNavbar() {
|
|||||||
) : <NavItems isAuthenticated={isAuthenticated} user={user} />}
|
) : <NavItems isAuthenticated={isAuthenticated} user={user} />}
|
||||||
|
|
||||||
{/* 右侧:日夜模式切换 + 登录/用户区 */}
|
{/* 右侧:日夜模式切换 + 登录/用户区 */}
|
||||||
<HStack spacing={4}>
|
<HStack spacing={{ base: 2, md: 4 }}>
|
||||||
<IconButton
|
<IconButton
|
||||||
aria-label="切换主题"
|
aria-label="切换主题"
|
||||||
icon={colorMode === 'light' ? <MoonIcon /> : <SunIcon />}
|
icon={colorMode === 'light' ? <MoonIcon /> : <SunIcon />}
|
||||||
onClick={toggleColorMode}
|
onClick={toggleColorMode}
|
||||||
variant="ghost"
|
variant="ghost"
|
||||||
size="sm"
|
size="sm"
|
||||||
|
minW={{ base: '36px', md: '40px' }}
|
||||||
|
minH={{ base: '36px', md: '40px' }}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
{/* 显示加载状态 */}
|
{/* 显示加载状态 */}
|
||||||
@@ -766,95 +773,9 @@ export default function HomeNavbar() {
|
|||||||
<Spinner size="sm" color="blue.500" />
|
<Spinner size="sm" color="blue.500" />
|
||||||
) : isAuthenticated && user ? (
|
) : isAuthenticated && user ? (
|
||||||
// 已登录状态 - 用户菜单 + 功能菜单排列
|
// 已登录状态 - 用户菜单 + 功能菜单排列
|
||||||
<HStack spacing={3}>
|
<HStack spacing={{ base: 2, md: 3 }}>
|
||||||
{/* 用户头像+订阅徽章组合 */}
|
{/* 自选股 - 移动端隐藏 */}
|
||||||
<HStack spacing={2} align="center">
|
{!isMobile && (
|
||||||
{/* 用户头像菜单 */}
|
|
||||||
<Menu>
|
|
||||||
<MenuButton
|
|
||||||
as={IconButton}
|
|
||||||
icon={
|
|
||||||
<Avatar
|
|
||||||
size="sm"
|
|
||||||
name={getDisplayName()}
|
|
||||||
src={user.avatar_url}
|
|
||||||
bg="blue.500"
|
|
||||||
border={subscriptionInfo.type !== 'free' ? '2px solid' : 'none'}
|
|
||||||
borderColor={
|
|
||||||
subscriptionInfo.type === 'max'
|
|
||||||
? 'purple.500'
|
|
||||||
: subscriptionInfo.type === 'pro'
|
|
||||||
? 'blue.500'
|
|
||||||
: 'transparent'
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
}
|
|
||||||
bg="transparent"
|
|
||||||
_hover={{ bg: useColorModeValue('gray.100', 'gray.700') }}
|
|
||||||
borderRadius="full"
|
|
||||||
position="relative"
|
|
||||||
aria-label="用户菜单"
|
|
||||||
>
|
|
||||||
</MenuButton>
|
|
||||||
<MenuList>
|
|
||||||
<Box px={3} py={2} borderBottom="1px" borderColor="gray.200">
|
|
||||||
<Text fontSize="sm" fontWeight="bold">{getDisplayName()}</Text>
|
|
||||||
<Text fontSize="xs" color="gray.500">{user.email}</Text>
|
|
||||||
{user.phone && (
|
|
||||||
<Text fontSize="xs" color="gray.500">{user.phone}</Text>
|
|
||||||
)}
|
|
||||||
{user.has_wechat && (
|
|
||||||
<Badge size="sm" colorScheme="green" mt={1}>微信已绑定</Badge>
|
|
||||||
)}
|
|
||||||
</Box>
|
|
||||||
{/* 账户管理组 */}
|
|
||||||
<MenuItem icon={<FiUser />} onClick={() => navigate('/home/profile')}>
|
|
||||||
个人资料
|
|
||||||
</MenuItem>
|
|
||||||
<MenuItem icon={<FiSettings />} onClick={() => navigate('/home/settings')}>
|
|
||||||
账户设置
|
|
||||||
</MenuItem>
|
|
||||||
<MenuDivider />
|
|
||||||
{/* 功能入口组 */}
|
|
||||||
<MenuItem icon={<FaCrown />} onClick={() => navigate('/home/pages/account/subscription')}>
|
|
||||||
订阅管理
|
|
||||||
</MenuItem>
|
|
||||||
<MenuDivider />
|
|
||||||
{/* 退出 */}
|
|
||||||
<MenuItem icon={<FiLogOut />} onClick={handleLogout} color="red.500">
|
|
||||||
退出登录
|
|
||||||
</MenuItem>
|
|
||||||
</MenuList>
|
|
||||||
</Menu>
|
|
||||||
|
|
||||||
{/* 订阅徽章按钮 - 点击打开订阅弹窗 */}
|
|
||||||
<SubscriptionButton
|
|
||||||
subscriptionInfo={subscriptionInfo}
|
|
||||||
onClick={() => setIsSubscriptionModalOpen(true)}
|
|
||||||
/>
|
|
||||||
|
|
||||||
{/* 订阅管理弹窗 - 只在打开时渲染 */}
|
|
||||||
{isSubscriptionModalOpen && (
|
|
||||||
<SubscriptionModal
|
|
||||||
isOpen={isSubscriptionModalOpen}
|
|
||||||
onClose={() => setIsSubscriptionModalOpen(false)}
|
|
||||||
subscriptionInfo={subscriptionInfo}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
</HStack>
|
|
||||||
|
|
||||||
{/* 个人中心快捷按钮 */}
|
|
||||||
<IconButton
|
|
||||||
icon={<FiHome />}
|
|
||||||
size="sm"
|
|
||||||
colorScheme="gray"
|
|
||||||
variant="ghost"
|
|
||||||
onClick={() => navigate('/home/center')}
|
|
||||||
aria-label="个人中心"
|
|
||||||
_hover={{ bg: 'gray.700' }}
|
|
||||||
/>
|
|
||||||
|
|
||||||
{/* 自选股 - 头像右侧 */}
|
|
||||||
<Menu onOpen={loadWatchlistQuotes}>
|
<Menu onOpen={loadWatchlistQuotes}>
|
||||||
<MenuButton
|
<MenuButton
|
||||||
as={Button}
|
as={Button}
|
||||||
@@ -929,8 +850,10 @@ export default function HomeNavbar() {
|
|||||||
)}
|
)}
|
||||||
</MenuList>
|
</MenuList>
|
||||||
</Menu>
|
</Menu>
|
||||||
|
)}
|
||||||
|
|
||||||
{/* 关注的事件 - 头像右侧 */}
|
{/* 关注的事件 - 头像右侧 - 移动端隐藏 */}
|
||||||
|
{!isMobile && (
|
||||||
<Menu onOpen={loadFollowingEvents}>
|
<Menu onOpen={loadFollowingEvents}>
|
||||||
<MenuButton
|
<MenuButton
|
||||||
as={Button}
|
as={Button}
|
||||||
@@ -1011,6 +934,105 @@ export default function HomeNavbar() {
|
|||||||
)}
|
)}
|
||||||
</MenuList>
|
</MenuList>
|
||||||
</Menu>
|
</Menu>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{/* 带会员标识的头像 - 点击打开订阅弹窗 */}
|
||||||
|
<Box
|
||||||
|
position="relative"
|
||||||
|
cursor="pointer"
|
||||||
|
onClick={() => setIsSubscriptionModalOpen(true)}
|
||||||
|
>
|
||||||
|
{/* 会员图标徽章 - 使用独立的 CrownTooltip 组件 */}
|
||||||
|
<CrownTooltip subscriptionInfo={subscriptionInfo} />
|
||||||
|
|
||||||
|
{/* 头像 - 带会员等级边框和详细信息 Tooltip */}
|
||||||
|
<Tooltip
|
||||||
|
label={<TooltipContent subscriptionInfo={subscriptionInfo} />}
|
||||||
|
placement="bottom"
|
||||||
|
hasArrow
|
||||||
|
bg={useColorModeValue('white', 'gray.800')}
|
||||||
|
borderRadius="lg"
|
||||||
|
border="1px solid"
|
||||||
|
borderColor={useColorModeValue('gray.200', 'gray.600')}
|
||||||
|
boxShadow="lg"
|
||||||
|
p={3}
|
||||||
|
>
|
||||||
|
<Avatar
|
||||||
|
size="sm"
|
||||||
|
name={getDisplayName()}
|
||||||
|
src={user.avatar_url}
|
||||||
|
bg="blue.500"
|
||||||
|
border={subscriptionInfo.type !== 'free' ? '2.5px solid' : 'none'}
|
||||||
|
borderColor={
|
||||||
|
subscriptionInfo.type === 'max' ? '#667eea' :
|
||||||
|
subscriptionInfo.type === 'pro' ? '#667eea' : 'transparent'
|
||||||
|
}
|
||||||
|
_hover={{
|
||||||
|
transform: 'scale(1.05)',
|
||||||
|
boxShadow: subscriptionInfo.type !== 'free'
|
||||||
|
? '0 4px 12px rgba(102, 126, 234, 0.4)'
|
||||||
|
: 'md',
|
||||||
|
}}
|
||||||
|
transition="all 0.2s"
|
||||||
|
/>
|
||||||
|
</Tooltip>
|
||||||
|
</Box>
|
||||||
|
|
||||||
|
{/* 订阅管理弹窗 - 只在打开时渲染 */}
|
||||||
|
{isSubscriptionModalOpen && (
|
||||||
|
<SubscriptionModal
|
||||||
|
isOpen={isSubscriptionModalOpen}
|
||||||
|
onClose={() => setIsSubscriptionModalOpen(false)}
|
||||||
|
subscriptionInfo={subscriptionInfo}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{/* 个人中心下拉菜单 */}
|
||||||
|
<Menu>
|
||||||
|
<MenuButton
|
||||||
|
as={Button}
|
||||||
|
size="sm"
|
||||||
|
variant="ghost"
|
||||||
|
rightIcon={<ChevronDownIcon />}
|
||||||
|
_hover={{ bg: useColorModeValue('gray.100', 'gray.700') }}
|
||||||
|
>
|
||||||
|
个人中心
|
||||||
|
</MenuButton>
|
||||||
|
<MenuList>
|
||||||
|
<Box px={3} py={2} borderBottom="1px" borderColor="gray.200">
|
||||||
|
<Text fontSize="sm" fontWeight="bold">{getDisplayName()}</Text>
|
||||||
|
<Text fontSize="xs" color="gray.500">{user.email}</Text>
|
||||||
|
{user.phone && (
|
||||||
|
<Text fontSize="xs" color="gray.500">{user.phone}</Text>
|
||||||
|
)}
|
||||||
|
{user.has_wechat && (
|
||||||
|
<Badge size="sm" colorScheme="green" mt={1}>微信已绑定</Badge>
|
||||||
|
)}
|
||||||
|
</Box>
|
||||||
|
{/* 前往个人中心 */}
|
||||||
|
<MenuItem icon={<FiHome />} onClick={() => navigate('/home/center')}>
|
||||||
|
前往个人中心
|
||||||
|
</MenuItem>
|
||||||
|
<MenuDivider />
|
||||||
|
{/* 账户管理组 */}
|
||||||
|
<MenuItem icon={<FiUser />} onClick={() => navigate('/home/profile')}>
|
||||||
|
个人资料
|
||||||
|
</MenuItem>
|
||||||
|
<MenuItem icon={<FiSettings />} onClick={() => navigate('/home/settings')}>
|
||||||
|
账户设置
|
||||||
|
</MenuItem>
|
||||||
|
<MenuDivider />
|
||||||
|
{/* 功能入口组 */}
|
||||||
|
<MenuItem icon={<FaCrown />} onClick={() => navigate('/home/pages/account/subscription')}>
|
||||||
|
订阅管理
|
||||||
|
</MenuItem>
|
||||||
|
<MenuDivider />
|
||||||
|
{/* 退出 */}
|
||||||
|
<MenuItem icon={<FiLogOut />} onClick={handleLogout} color="red.500">
|
||||||
|
退出登录
|
||||||
|
</MenuItem>
|
||||||
|
</MenuList>
|
||||||
|
</Menu>
|
||||||
</HStack>
|
</HStack>
|
||||||
) : (
|
) : (
|
||||||
// 未登录状态 - 单一按钮
|
// 未登录状态 - 单一按钮
|
||||||
|
|||||||
Reference in New Issue
Block a user