refactor(WatchSidebar): 优化三个子组件
- FollowingEventsPanel: 添加滚动区域容器,移除数量限制 - MyCommentsTab: 添加滚动区域,移除 maxDisplay 限制 - WatchlistPanel: 优化滚动区域样式和布局 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -112,61 +112,62 @@ const EventsTabContent = ({ events, onEventClick, onAddEvent }) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<VStack spacing={1.5} align="stretch">
|
<Box
|
||||||
{events.slice(0, 6).map((event) => {
|
maxH="280px"
|
||||||
const avgChg = event.related_avg_chg;
|
overflowY="auto"
|
||||||
const isUp = avgChg > 0;
|
css={{
|
||||||
const changeColor = isUp ? '#EF4444' : avgChg < 0 ? '#22C55E' : 'rgba(255, 255, 255, 0.6)';
|
'&::-webkit-scrollbar': { width: '0px' },
|
||||||
|
'&:hover::-webkit-scrollbar': { width: '4px' },
|
||||||
|
'&::-webkit-scrollbar-track': { background: 'transparent' },
|
||||||
|
'&::-webkit-scrollbar-thumb': {
|
||||||
|
background: 'rgba(255, 255, 255, 0.2)',
|
||||||
|
borderRadius: '2px',
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<VStack spacing={1.5} align="stretch">
|
||||||
|
{events.map((event) => {
|
||||||
|
const avgChg = event.related_avg_chg;
|
||||||
|
const isUp = avgChg > 0;
|
||||||
|
const changeColor = isUp ? '#EF4444' : avgChg < 0 ? '#22C55E' : 'rgba(255, 255, 255, 0.6)';
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Box
|
<Box
|
||||||
key={event.id}
|
key={event.id}
|
||||||
py={2}
|
py={2}
|
||||||
px={2}
|
px={2}
|
||||||
cursor="pointer"
|
cursor="pointer"
|
||||||
borderRadius="md"
|
borderRadius="md"
|
||||||
bg="rgba(37, 37, 64, 0.3)"
|
bg="rgba(37, 37, 64, 0.3)"
|
||||||
_hover={{ bg: 'rgba(37, 37, 64, 0.6)' }}
|
_hover={{ bg: 'rgba(37, 37, 64, 0.6)' }}
|
||||||
onClick={() => onEventClick?.(event)}
|
onClick={() => onEventClick?.(event)}
|
||||||
>
|
|
||||||
<Text
|
|
||||||
fontSize="xs"
|
|
||||||
fontWeight="medium"
|
|
||||||
color="rgba(255, 255, 255, 0.9)"
|
|
||||||
noOfLines={2}
|
|
||||||
mb={1}
|
|
||||||
lineHeight="1.4"
|
|
||||||
>
|
>
|
||||||
{event.title}
|
<Text
|
||||||
</Text>
|
fontSize="xs"
|
||||||
<HStack justify="space-between" fontSize="10px">
|
fontWeight="medium"
|
||||||
<HStack spacing={1} color="rgba(255, 255, 255, 0.4)">
|
color="rgba(255, 255, 255, 0.9)"
|
||||||
<Icon as={Users} boxSize={2.5} />
|
noOfLines={2}
|
||||||
<Text>{event.follower_count || 0}</Text>
|
mb={1}
|
||||||
|
lineHeight="1.4"
|
||||||
|
>
|
||||||
|
{event.title}
|
||||||
|
</Text>
|
||||||
|
<HStack justify="space-between" fontSize="10px">
|
||||||
|
<HStack spacing={1} color="rgba(255, 255, 255, 0.4)">
|
||||||
|
<Icon as={Users} boxSize={2.5} />
|
||||||
|
<Text>{event.follower_count || 0}</Text>
|
||||||
|
</HStack>
|
||||||
|
{avgChg !== undefined && avgChg !== null && (
|
||||||
|
<Text color={changeColor} fontWeight="medium">
|
||||||
|
{isUp ? '+' : ''}{Number(avgChg).toFixed(2)}%
|
||||||
|
</Text>
|
||||||
|
)}
|
||||||
</HStack>
|
</HStack>
|
||||||
{avgChg !== undefined && avgChg !== null && (
|
</Box>
|
||||||
<Text color={changeColor} fontWeight="medium">
|
);
|
||||||
{isUp ? '+' : ''}{Number(avgChg).toFixed(2)}%
|
})}
|
||||||
</Text>
|
</VStack>
|
||||||
)}
|
</Box>
|
||||||
</HStack>
|
|
||||||
</Box>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
{events.length > 6 && (
|
|
||||||
<Text
|
|
||||||
fontSize="xs"
|
|
||||||
color="rgba(212, 175, 55, 0.7)"
|
|
||||||
textAlign="center"
|
|
||||||
cursor="pointer"
|
|
||||||
py={1}
|
|
||||||
_hover={{ color: 'rgba(212, 175, 55, 0.9)' }}
|
|
||||||
onClick={onAddEvent}
|
|
||||||
>
|
|
||||||
查看全部 ({events.length})
|
|
||||||
</Text>
|
|
||||||
)}
|
|
||||||
</VStack>
|
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -33,10 +33,7 @@ const truncateText = (text, maxLength = 50) => {
|
|||||||
const MyCommentsTab = ({
|
const MyCommentsTab = ({
|
||||||
comments = [],
|
comments = [],
|
||||||
onCommentClick,
|
onCommentClick,
|
||||||
maxDisplay = 5,
|
|
||||||
}) => {
|
}) => {
|
||||||
const displayComments = comments.slice(0, maxDisplay);
|
|
||||||
|
|
||||||
if (comments.length === 0) {
|
if (comments.length === 0) {
|
||||||
return (
|
return (
|
||||||
<Box py={4} textAlign="center">
|
<Box py={4} textAlign="center">
|
||||||
@@ -49,72 +46,72 @@ const MyCommentsTab = ({
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<VStack spacing={1.5} align="stretch">
|
<Box
|
||||||
{displayComments.map((comment) => (
|
maxH="280px"
|
||||||
<Box
|
overflowY="auto"
|
||||||
key={comment.id}
|
css={{
|
||||||
py={2}
|
'&::-webkit-scrollbar': { width: '0px' },
|
||||||
px={2}
|
'&:hover::-webkit-scrollbar': { width: '4px' },
|
||||||
cursor="pointer"
|
'&::-webkit-scrollbar-track': { background: 'transparent' },
|
||||||
borderRadius="md"
|
'&::-webkit-scrollbar-thumb': {
|
||||||
bg="rgba(37, 37, 64, 0.3)"
|
background: 'rgba(255, 255, 255, 0.2)',
|
||||||
_hover={{ bg: 'rgba(37, 37, 64, 0.6)' }}
|
borderRadius: '2px',
|
||||||
onClick={() => onCommentClick?.(comment)}
|
},
|
||||||
>
|
}}
|
||||||
{/* 评论内容 */}
|
>
|
||||||
<Text
|
<VStack spacing={1.5} align="stretch">
|
||||||
fontSize="xs"
|
{comments.map((comment) => (
|
||||||
color="rgba(255, 255, 255, 0.85)"
|
<Box
|
||||||
noOfLines={2}
|
key={comment.id}
|
||||||
mb={1}
|
py={2}
|
||||||
lineHeight="1.4"
|
px={2}
|
||||||
|
cursor="pointer"
|
||||||
|
borderRadius="md"
|
||||||
|
bg="rgba(37, 37, 64, 0.3)"
|
||||||
|
_hover={{ bg: 'rgba(37, 37, 64, 0.6)' }}
|
||||||
|
onClick={() => onCommentClick?.(comment)}
|
||||||
>
|
>
|
||||||
{truncateText(comment.content, 60)}
|
{/* 评论内容 */}
|
||||||
</Text>
|
|
||||||
|
|
||||||
{/* 关联事件 */}
|
|
||||||
{comment.event_title && (
|
|
||||||
<Text
|
<Text
|
||||||
fontSize="10px"
|
fontSize="xs"
|
||||||
color="rgba(212, 175, 55, 0.7)"
|
color="rgba(255, 255, 255, 0.85)"
|
||||||
noOfLines={1}
|
noOfLines={2}
|
||||||
mb={1}
|
mb={1}
|
||||||
|
lineHeight="1.4"
|
||||||
>
|
>
|
||||||
📌 {truncateText(comment.event_title, 30)}
|
{truncateText(comment.content, 60)}
|
||||||
</Text>
|
</Text>
|
||||||
)}
|
|
||||||
|
|
||||||
{/* 底部信息:点赞、回复、时间 */}
|
{/* 关联事件 */}
|
||||||
<HStack justify="space-between" fontSize="10px" color="rgba(255, 255, 255, 0.4)">
|
{comment.event_title && (
|
||||||
<HStack spacing={2}>
|
<Text
|
||||||
<HStack spacing={0.5}>
|
fontSize="10px"
|
||||||
<Icon as={ThumbsUp} boxSize={2.5} />
|
color="rgba(212, 175, 55, 0.7)"
|
||||||
<Text>{comment.like_count || 0}</Text>
|
noOfLines={1}
|
||||||
</HStack>
|
mb={1}
|
||||||
<HStack spacing={0.5}>
|
>
|
||||||
<Icon as={MessageCircle} boxSize={2.5} />
|
📌 {truncateText(comment.event_title, 30)}
|
||||||
<Text>{comment.reply_count || 0}</Text>
|
</Text>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{/* 底部信息:点赞、回复、时间 */}
|
||||||
|
<HStack justify="space-between" fontSize="10px" color="rgba(255, 255, 255, 0.4)">
|
||||||
|
<HStack spacing={2}>
|
||||||
|
<HStack spacing={0.5}>
|
||||||
|
<Icon as={ThumbsUp} boxSize={2.5} />
|
||||||
|
<Text>{comment.like_count || 0}</Text>
|
||||||
|
</HStack>
|
||||||
|
<HStack spacing={0.5}>
|
||||||
|
<Icon as={MessageCircle} boxSize={2.5} />
|
||||||
|
<Text>{comment.reply_count || 0}</Text>
|
||||||
|
</HStack>
|
||||||
</HStack>
|
</HStack>
|
||||||
|
<Text>{formatRelativeTime(comment.created_at)}</Text>
|
||||||
</HStack>
|
</HStack>
|
||||||
<Text>{formatRelativeTime(comment.created_at)}</Text>
|
</Box>
|
||||||
</HStack>
|
))}
|
||||||
</Box>
|
</VStack>
|
||||||
))}
|
</Box>
|
||||||
|
|
||||||
{/* 查看更多 */}
|
|
||||||
{comments.length > maxDisplay && (
|
|
||||||
<Text
|
|
||||||
fontSize="xs"
|
|
||||||
color="rgba(212, 175, 55, 0.7)"
|
|
||||||
textAlign="center"
|
|
||||||
cursor="pointer"
|
|
||||||
py={1}
|
|
||||||
_hover={{ color: 'rgba(212, 175, 55, 0.9)' }}
|
|
||||||
>
|
|
||||||
查看全部 ({comments.length})
|
|
||||||
</Text>
|
|
||||||
)}
|
|
||||||
</VStack>
|
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -32,81 +32,82 @@ const WatchlistPanel = ({
|
|||||||
/>
|
/>
|
||||||
</HStack>
|
</HStack>
|
||||||
|
|
||||||
{/* 股票列表 */}
|
{/* 股票列表 - 固定高度可滚动 */}
|
||||||
<VStack spacing={1} align="stretch">
|
{watchlist.length === 0 ? (
|
||||||
{watchlist.length === 0 ? (
|
<Box
|
||||||
<Box
|
py={4}
|
||||||
py={4}
|
textAlign="center"
|
||||||
textAlign="center"
|
cursor="pointer"
|
||||||
cursor="pointer"
|
onClick={onAddStock}
|
||||||
onClick={onAddStock}
|
_hover={{ bg: 'rgba(255, 255, 255, 0.05)' }}
|
||||||
_hover={{ bg: 'rgba(255, 255, 255, 0.05)' }}
|
borderRadius="md"
|
||||||
borderRadius="md"
|
>
|
||||||
>
|
<Icon as={BarChart2} boxSize={6} color="rgba(255, 255, 255, 0.2)" mb={1} />
|
||||||
<Icon as={BarChart2} boxSize={6} color="rgba(255, 255, 255, 0.2)" mb={1} />
|
<Text fontSize="xs" color="rgba(255, 255, 255, 0.4)">
|
||||||
<Text fontSize="xs" color="rgba(255, 255, 255, 0.4)">
|
添加自选股
|
||||||
添加自选股
|
|
||||||
</Text>
|
|
||||||
</Box>
|
|
||||||
) : (
|
|
||||||
watchlist.slice(0, 8).map((stock) => {
|
|
||||||
const quote = realtimeQuotes[stock.stock_code];
|
|
||||||
const changePercent = quote?.change_percent ?? stock.change_percent;
|
|
||||||
const isUp = changePercent > 0;
|
|
||||||
const changeColor = isUp ? '#EF4444' : changePercent < 0 ? '#22C55E' : 'rgba(255, 255, 255, 0.6)';
|
|
||||||
|
|
||||||
return (
|
|
||||||
<HStack
|
|
||||||
key={stock.stock_code}
|
|
||||||
py={1.5}
|
|
||||||
px={2}
|
|
||||||
justify="space-between"
|
|
||||||
cursor="pointer"
|
|
||||||
borderRadius="md"
|
|
||||||
_hover={{ bg: 'rgba(255, 255, 255, 0.05)' }}
|
|
||||||
onClick={() => onStockClick?.(stock)}
|
|
||||||
>
|
|
||||||
<VStack align="start" spacing={0} flex={1} minW={0}>
|
|
||||||
<Text
|
|
||||||
fontSize="xs"
|
|
||||||
fontWeight="medium"
|
|
||||||
color="rgba(255, 255, 255, 0.9)"
|
|
||||||
noOfLines={1}
|
|
||||||
>
|
|
||||||
{stock.stock_name || stock.stock_code}
|
|
||||||
</Text>
|
|
||||||
<Text fontSize="10px" color="rgba(255, 255, 255, 0.4)">
|
|
||||||
{stock.stock_code}
|
|
||||||
</Text>
|
|
||||||
</VStack>
|
|
||||||
<VStack align="end" spacing={0}>
|
|
||||||
<Text fontSize="xs" fontWeight="bold" color={changeColor}>
|
|
||||||
{quote?.current_price?.toFixed(2) || stock.current_price || '--'}
|
|
||||||
</Text>
|
|
||||||
<Text fontSize="10px" color={changeColor}>
|
|
||||||
{changePercent !== undefined && changePercent !== null
|
|
||||||
? `${isUp ? '+' : ''}${Number(changePercent).toFixed(2)}%`
|
|
||||||
: '--'}
|
|
||||||
</Text>
|
|
||||||
</VStack>
|
|
||||||
</HStack>
|
|
||||||
);
|
|
||||||
})
|
|
||||||
)}
|
|
||||||
{watchlist.length > 8 && (
|
|
||||||
<Text
|
|
||||||
fontSize="xs"
|
|
||||||
color="rgba(212, 175, 55, 0.7)"
|
|
||||||
textAlign="center"
|
|
||||||
cursor="pointer"
|
|
||||||
py={1}
|
|
||||||
_hover={{ color: 'rgba(212, 175, 55, 0.9)' }}
|
|
||||||
onClick={onAddStock}
|
|
||||||
>
|
|
||||||
查看全部 ({watchlist.length})
|
|
||||||
</Text>
|
</Text>
|
||||||
)}
|
</Box>
|
||||||
</VStack>
|
) : (
|
||||||
|
<Box
|
||||||
|
maxH="240px"
|
||||||
|
overflowY="auto"
|
||||||
|
css={{
|
||||||
|
'&::-webkit-scrollbar': { width: '0px' },
|
||||||
|
'&:hover::-webkit-scrollbar': { width: '4px' },
|
||||||
|
'&::-webkit-scrollbar-track': { background: 'transparent' },
|
||||||
|
'&::-webkit-scrollbar-thumb': {
|
||||||
|
background: 'rgba(255, 255, 255, 0.2)',
|
||||||
|
borderRadius: '2px',
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<VStack spacing={1} align="stretch">
|
||||||
|
{watchlist.map((stock) => {
|
||||||
|
const quote = realtimeQuotes[stock.stock_code];
|
||||||
|
const changePercent = quote?.change_percent ?? stock.change_percent;
|
||||||
|
const isUp = changePercent > 0;
|
||||||
|
const changeColor = isUp ? '#EF4444' : changePercent < 0 ? '#22C55E' : 'rgba(255, 255, 255, 0.6)';
|
||||||
|
|
||||||
|
return (
|
||||||
|
<HStack
|
||||||
|
key={stock.stock_code}
|
||||||
|
py={1.5}
|
||||||
|
px={2}
|
||||||
|
justify="space-between"
|
||||||
|
cursor="pointer"
|
||||||
|
borderRadius="md"
|
||||||
|
_hover={{ bg: 'rgba(255, 255, 255, 0.05)' }}
|
||||||
|
onClick={() => onStockClick?.(stock)}
|
||||||
|
>
|
||||||
|
<VStack align="start" spacing={0} flex={1} minW={0}>
|
||||||
|
<Text
|
||||||
|
fontSize="xs"
|
||||||
|
fontWeight="medium"
|
||||||
|
color="rgba(255, 255, 255, 0.9)"
|
||||||
|
noOfLines={1}
|
||||||
|
>
|
||||||
|
{stock.stock_name || stock.stock_code}
|
||||||
|
</Text>
|
||||||
|
<Text fontSize="10px" color="rgba(255, 255, 255, 0.4)">
|
||||||
|
{stock.stock_code}
|
||||||
|
</Text>
|
||||||
|
</VStack>
|
||||||
|
<VStack align="end" spacing={0}>
|
||||||
|
<Text fontSize="xs" fontWeight="bold" color={changeColor}>
|
||||||
|
{quote?.current_price?.toFixed(2) || stock.current_price || '--'}
|
||||||
|
</Text>
|
||||||
|
<Text fontSize="10px" color={changeColor}>
|
||||||
|
{changePercent !== undefined && changePercent !== null
|
||||||
|
? `${isUp ? '+' : ''}${Number(changePercent).toFixed(2)}%`
|
||||||
|
: '--'}
|
||||||
|
</Text>
|
||||||
|
</VStack>
|
||||||
|
</HStack>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</VStack>
|
||||||
|
</Box>
|
||||||
|
)}
|
||||||
</Box>
|
</Box>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user