feat: 添加 EventScrollList.js 组件
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
// src/views/Community/components/DynamicNewsCard.js
|
||||
// 横向滚动事件卡片组件(实时要闻·动态追踪)
|
||||
|
||||
import React, { forwardRef, useRef, useState, useEffect } from 'react';
|
||||
import React, { forwardRef, useState, useEffect } from 'react';
|
||||
import {
|
||||
Card,
|
||||
CardHeader,
|
||||
@@ -13,13 +13,12 @@ import {
|
||||
Heading,
|
||||
Text,
|
||||
Badge,
|
||||
IconButton,
|
||||
Center,
|
||||
Spinner,
|
||||
useColorModeValue
|
||||
} from '@chakra-ui/react';
|
||||
import { ChevronLeftIcon, ChevronRightIcon, TimeIcon } from '@chakra-ui/icons';
|
||||
import DynamicNewsEventCard from './EventCard/DynamicNewsEventCard';
|
||||
import { TimeIcon } from '@chakra-ui/icons';
|
||||
import EventScrollList from './DynamicNewsCard/EventScrollList';
|
||||
import DynamicNewsDetailPanel from './DynamicNewsDetail';
|
||||
|
||||
/**
|
||||
@@ -41,9 +40,6 @@ const DynamicNewsCard = forwardRef(({
|
||||
}, ref) => {
|
||||
const cardBg = useColorModeValue('white', 'gray.800');
|
||||
const borderColor = useColorModeValue('gray.200', 'gray.700');
|
||||
const scrollContainerRef = useRef(null);
|
||||
const [showLeftArrow, setShowLeftArrow] = useState(false);
|
||||
const [showRightArrow, setShowRightArrow] = useState(true);
|
||||
const [selectedEvent, setSelectedEvent] = useState(null);
|
||||
|
||||
// 默认选中第一个事件
|
||||
@@ -53,48 +49,6 @@ const DynamicNewsCard = forwardRef(({
|
||||
}
|
||||
}, [events, selectedEvent]);
|
||||
|
||||
// 滚动到左侧
|
||||
const scrollLeft = () => {
|
||||
if (scrollContainerRef.current) {
|
||||
scrollContainerRef.current.scrollBy({
|
||||
left: -400,
|
||||
behavior: 'smooth'
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
// 滚动到右侧
|
||||
const scrollRight = () => {
|
||||
if (scrollContainerRef.current) {
|
||||
scrollContainerRef.current.scrollBy({
|
||||
left: 400,
|
||||
behavior: 'smooth'
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
// 监听滚动位置,更新箭头显示状态
|
||||
const handleScroll = (e) => {
|
||||
const container = e.target;
|
||||
const scrollLeft = container.scrollLeft;
|
||||
const scrollWidth = container.scrollWidth;
|
||||
const clientWidth = container.clientWidth;
|
||||
|
||||
setShowLeftArrow(scrollLeft > 0);
|
||||
setShowRightArrow(scrollLeft < scrollWidth - clientWidth - 10);
|
||||
};
|
||||
|
||||
// 时间轴样式配置
|
||||
const getTimelineBoxStyle = () => {
|
||||
return {
|
||||
bg: useColorModeValue('gray.50', 'gray.700'),
|
||||
borderColor: useColorModeValue('gray.400', 'gray.500'),
|
||||
borderWidth: '2px',
|
||||
textColor: useColorModeValue('blue.600', 'blue.400'),
|
||||
boxShadow: 'sm',
|
||||
};
|
||||
};
|
||||
|
||||
return (
|
||||
<Card ref={ref} {...rest} bg={cardBg} borderColor={borderColor} mb={4}>
|
||||
{/* 标题部分 */}
|
||||
@@ -142,106 +96,12 @@ const DynamicNewsCard = forwardRef(({
|
||||
|
||||
{/* 横向滚动事件列表 */}
|
||||
{!loading && events && events.length > 0 && (
|
||||
<Box position="relative">
|
||||
{/* 左侧滚动按钮 */}
|
||||
{showLeftArrow && (
|
||||
<IconButton
|
||||
icon={<ChevronLeftIcon boxSize={6} />}
|
||||
position="absolute"
|
||||
left="-4"
|
||||
top="50%"
|
||||
transform="translateY(-50%)"
|
||||
zIndex={2}
|
||||
onClick={scrollLeft}
|
||||
colorScheme="blue"
|
||||
variant="solid"
|
||||
size="md"
|
||||
borderRadius="full"
|
||||
shadow="md"
|
||||
aria-label="向左滚动"
|
||||
/>
|
||||
)}
|
||||
|
||||
{/* 右侧滚动按钮 */}
|
||||
{showRightArrow && (
|
||||
<IconButton
|
||||
icon={<ChevronRightIcon boxSize={6} />}
|
||||
position="absolute"
|
||||
right="-4"
|
||||
top="50%"
|
||||
transform="translateY(-50%)"
|
||||
zIndex={2}
|
||||
onClick={scrollRight}
|
||||
colorScheme="blue"
|
||||
variant="solid"
|
||||
size="md"
|
||||
borderRadius="full"
|
||||
shadow="md"
|
||||
aria-label="向右滚动"
|
||||
/>
|
||||
)}
|
||||
|
||||
{/* 横向滚动容器 */}
|
||||
<Flex
|
||||
ref={scrollContainerRef}
|
||||
overflowX="auto"
|
||||
overflowY="hidden"
|
||||
gap={4}
|
||||
py={4}
|
||||
px={2}
|
||||
onScroll={handleScroll}
|
||||
css={{
|
||||
'&::-webkit-scrollbar': {
|
||||
height: '8px',
|
||||
},
|
||||
'&::-webkit-scrollbar-track': {
|
||||
background: useColorModeValue('#f1f1f1', '#2D3748'),
|
||||
borderRadius: '10px',
|
||||
},
|
||||
'&::-webkit-scrollbar-thumb': {
|
||||
background: useColorModeValue('#888', '#4A5568'),
|
||||
borderRadius: '10px',
|
||||
},
|
||||
'&::-webkit-scrollbar-thumb:hover': {
|
||||
background: useColorModeValue('#555', '#718096'),
|
||||
},
|
||||
// 平滑滚动
|
||||
scrollBehavior: 'smooth',
|
||||
// 触摸设备优化
|
||||
WebkitOverflowScrolling: 'touch',
|
||||
}}
|
||||
>
|
||||
{events.map((event, index) => (
|
||||
<Box
|
||||
key={event.id}
|
||||
minW="calc((100% - 64px) / 5)"
|
||||
maxW="calc((100% - 64px) / 5)"
|
||||
flexShrink={0}
|
||||
>
|
||||
<DynamicNewsEventCard
|
||||
event={event}
|
||||
index={index}
|
||||
isFollowing={false}
|
||||
followerCount={event.follower_count || 0}
|
||||
isSelected={selectedEvent?.id === event.id}
|
||||
onEventClick={(clickedEvent) => {
|
||||
setSelectedEvent(clickedEvent);
|
||||
// 只更新详情面板,不触发父组件回调
|
||||
}}
|
||||
onTitleClick={(e) => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
setSelectedEvent(event);
|
||||
// 只更新详情面板,不触发父组件回调
|
||||
}}
|
||||
onToggleFollow={() => {}}
|
||||
timelineStyle={getTimelineBoxStyle()}
|
||||
borderColor={borderColor}
|
||||
/>
|
||||
</Box>
|
||||
))}
|
||||
</Flex>
|
||||
</Box>
|
||||
<EventScrollList
|
||||
events={events}
|
||||
selectedEvent={selectedEvent}
|
||||
onEventSelect={setSelectedEvent}
|
||||
borderColor={borderColor}
|
||||
/>
|
||||
)}
|
||||
|
||||
{/* 详情面板 */}
|
||||
|
||||
@@ -0,0 +1,175 @@
|
||||
// src/views/Community/components/DynamicNewsCard/EventScrollList.js
|
||||
// 横向滚动事件列表组件
|
||||
|
||||
import React, { useRef, useState } from 'react';
|
||||
import {
|
||||
Box,
|
||||
Flex,
|
||||
IconButton,
|
||||
useColorModeValue
|
||||
} from '@chakra-ui/react';
|
||||
import { ChevronLeftIcon, ChevronRightIcon } from '@chakra-ui/icons';
|
||||
import DynamicNewsEventCard from '../EventCard/DynamicNewsEventCard';
|
||||
|
||||
/**
|
||||
* 横向滚动事件列表组件
|
||||
* @param {Array} events - 事件列表
|
||||
* @param {Object} selectedEvent - 当前选中的事件
|
||||
* @param {Function} onEventSelect - 事件选择回调
|
||||
* @param {string} borderColor - 边框颜色
|
||||
*/
|
||||
const EventScrollList = ({
|
||||
events,
|
||||
selectedEvent,
|
||||
onEventSelect,
|
||||
borderColor
|
||||
}) => {
|
||||
const scrollContainerRef = useRef(null);
|
||||
const [showLeftArrow, setShowLeftArrow] = useState(false);
|
||||
const [showRightArrow, setShowRightArrow] = useState(true);
|
||||
|
||||
// 滚动到左侧
|
||||
const scrollLeft = () => {
|
||||
if (scrollContainerRef.current) {
|
||||
scrollContainerRef.current.scrollBy({
|
||||
left: -400,
|
||||
behavior: 'smooth'
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
// 滚动到右侧
|
||||
const scrollRight = () => {
|
||||
if (scrollContainerRef.current) {
|
||||
scrollContainerRef.current.scrollBy({
|
||||
left: 400,
|
||||
behavior: 'smooth'
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
// 监听滚动位置,更新箭头显示状态
|
||||
const handleScroll = (e) => {
|
||||
const container = e.target;
|
||||
const scrollLeft = container.scrollLeft;
|
||||
const scrollWidth = container.scrollWidth;
|
||||
const clientWidth = container.clientWidth;
|
||||
|
||||
setShowLeftArrow(scrollLeft > 0);
|
||||
setShowRightArrow(scrollLeft < scrollWidth - clientWidth - 10);
|
||||
};
|
||||
|
||||
// 时间轴样式配置
|
||||
const getTimelineBoxStyle = () => {
|
||||
return {
|
||||
bg: useColorModeValue('gray.50', 'gray.700'),
|
||||
borderColor: useColorModeValue('gray.400', 'gray.500'),
|
||||
borderWidth: '2px',
|
||||
textColor: useColorModeValue('blue.600', 'blue.400'),
|
||||
boxShadow: 'sm',
|
||||
};
|
||||
};
|
||||
|
||||
return (
|
||||
<Box position="relative">
|
||||
{/* 左侧滚动按钮 */}
|
||||
{showLeftArrow && (
|
||||
<IconButton
|
||||
icon={<ChevronLeftIcon boxSize={6} />}
|
||||
position="absolute"
|
||||
left="-4"
|
||||
top="50%"
|
||||
transform="translateY(-50%)"
|
||||
zIndex={2}
|
||||
onClick={scrollLeft}
|
||||
colorScheme="blue"
|
||||
variant="solid"
|
||||
size="md"
|
||||
borderRadius="full"
|
||||
shadow="md"
|
||||
aria-label="向左滚动"
|
||||
/>
|
||||
)}
|
||||
|
||||
{/* 右侧滚动按钮 */}
|
||||
{showRightArrow && (
|
||||
<IconButton
|
||||
icon={<ChevronRightIcon boxSize={6} />}
|
||||
position="absolute"
|
||||
right="-4"
|
||||
top="50%"
|
||||
transform="translateY(-50%)"
|
||||
zIndex={2}
|
||||
onClick={scrollRight}
|
||||
colorScheme="blue"
|
||||
variant="solid"
|
||||
size="md"
|
||||
borderRadius="full"
|
||||
shadow="md"
|
||||
aria-label="向右滚动"
|
||||
/>
|
||||
)}
|
||||
|
||||
{/* 横向滚动容器 */}
|
||||
<Flex
|
||||
ref={scrollContainerRef}
|
||||
overflowX="auto"
|
||||
overflowY="hidden"
|
||||
gap={4}
|
||||
py={4}
|
||||
px={2}
|
||||
onScroll={handleScroll}
|
||||
css={{
|
||||
'&::-webkit-scrollbar': {
|
||||
height: '8px',
|
||||
},
|
||||
'&::-webkit-scrollbar-track': {
|
||||
background: useColorModeValue('#f1f1f1', '#2D3748'),
|
||||
borderRadius: '10px',
|
||||
},
|
||||
'&::-webkit-scrollbar-thumb': {
|
||||
background: useColorModeValue('#888', '#4A5568'),
|
||||
borderRadius: '10px',
|
||||
},
|
||||
'&::-webkit-scrollbar-thumb:hover': {
|
||||
background: useColorModeValue('#555', '#718096'),
|
||||
},
|
||||
// 平滑滚动
|
||||
scrollBehavior: 'smooth',
|
||||
// 触摸设备优化
|
||||
WebkitOverflowScrolling: 'touch',
|
||||
}}
|
||||
>
|
||||
{events.map((event, index) => (
|
||||
<Box
|
||||
key={event.id}
|
||||
minW="calc((100% - 64px) / 5)"
|
||||
maxW="calc((100% - 64px) / 5)"
|
||||
flexShrink={0}
|
||||
>
|
||||
<DynamicNewsEventCard
|
||||
event={event}
|
||||
index={index}
|
||||
isFollowing={false}
|
||||
followerCount={event.follower_count || 0}
|
||||
isSelected={selectedEvent?.id === event.id}
|
||||
onEventClick={(clickedEvent) => {
|
||||
onEventSelect(clickedEvent);
|
||||
}}
|
||||
onTitleClick={(e) => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
onEventSelect(event);
|
||||
}}
|
||||
onToggleFollow={() => {}}
|
||||
timelineStyle={getTimelineBoxStyle()}
|
||||
borderColor={borderColor}
|
||||
/>
|
||||
</Box>
|
||||
))}
|
||||
</Flex>
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
|
||||
export default EventScrollList;
|
||||
Reference in New Issue
Block a user