update ui

This commit is contained in:
2025-11-14 07:25:12 +08:00
parent 5e70f4443d
commit eac3b09a95
7 changed files with 1932 additions and 15 deletions

View File

@@ -2,10 +2,25 @@
// 纵向分栏模式布局组件
import React, { useState } from 'react';
import { Box, VStack, Flex, Center, Text, useBreakpointValue } from '@chakra-ui/react';
import {
Box,
VStack,
Flex,
Center,
Text,
useBreakpointValue,
Modal,
ModalOverlay,
ModalContent,
ModalHeader,
ModalBody,
ModalCloseButton,
useDisclosure
} from '@chakra-ui/react';
import { InfoIcon } from '@chakra-ui/icons';
import HorizontalDynamicNewsEventCard from '../EventCard/HorizontalDynamicNewsEventCard';
import EventDetailScrollPanel from './EventDetailScrollPanel';
import DynamicNewsDetailPanel from '../../DynamicNewsDetail/DynamicNewsDetailPanel';
/**
* 纵向分栏模式布局
@@ -38,6 +53,20 @@ const VerticalModeLayout = ({
const flexDirection = useBreakpointValue({ base: 'column', lg: 'row' });
const gap = useBreakpointValue({ base: 3, lg: 6 });
// 移动端模态框控制
const { isOpen: isMobileModalOpen, onOpen: onMobileModalOpen, onClose: onMobileModalClose } = useDisclosure();
const [mobileSelectedEvent, setMobileSelectedEvent] = useState(null);
// 处理移动端事件点击
const handleMobileEventClick = (event) => {
if (isMobile) {
setMobileSelectedEvent(event);
onMobileModalOpen();
} else {
onEventSelect(event);
}
};
// 固定布局比例左侧4右侧6- 平衡布局,确保左侧有足够空间显示内容
const leftFlex = '4';
const rightFlex = '6';
@@ -89,7 +118,7 @@ const VerticalModeLayout = ({
key={event.id}
event={event}
isSelected={selectedEvent?.id === event.id}
onEventClick={() => onEventSelect(event)}
onEventClick={() => handleMobileEventClick(event)}
isFollowing={eventFollowStatus[event.id]?.isFollowing}
followerCount={eventFollowStatus[event.id]?.followerCount}
onToggleFollow={onToggleFollow}
@@ -133,6 +162,24 @@ const VerticalModeLayout = ({
/>
</Box>
)}
{/* 移动端详情弹窗 */}
{isMobile && (
<Modal isOpen={isMobileModalOpen} onClose={onMobileModalClose} size="full" scrollBehavior="inside">
<ModalOverlay bg="blackAlpha.800" backdropFilter="blur(10px)" />
<ModalContent maxW="100vw" m={0} borderRadius={0}>
<ModalHeader bg="gray.900" color="white" borderBottom="1px solid" borderColor="gray.700">
{mobileSelectedEvent?.title || '事件详情'}
</ModalHeader>
<ModalCloseButton color="white" />
<ModalBody p={0} bg="gray.900">
{mobileSelectedEvent && (
<DynamicNewsDetailPanel event={mobileSelectedEvent} showHeader={false} />
)}
</ModalBody>
</ModalContent>
</Modal>
)}
</Flex>
);
};

View File

@@ -3,7 +3,7 @@
import React, { useRef, useMemo, useEffect } from 'react';
import { useVirtualizer } from '@tanstack/react-virtual';
import { Box, Grid, Spinner, Text, VStack, Center, HStack, IconButton } from '@chakra-ui/react';
import { Box, Grid, Spinner, Text, VStack, Center, HStack, IconButton, useBreakpointValue } from '@chakra-ui/react';
import { RepeatIcon } from '@chakra-ui/icons';
import { useColorModeValue } from '@chakra-ui/react';
import DynamicNewsEventCard from '../EventCard/DynamicNewsEventCard';
@@ -52,14 +52,26 @@ const VirtualizedFourRowGrid = ({
const scrollbarThumbBg = useColorModeValue('#888', '#4A5568');
const scrollbarThumbHoverBg = useColorModeValue('#555', '#718096');
// 将事件按 columnsPerRow 个一组分成行
// 响应式列数
const responsiveColumns = useBreakpointValue({
base: 1, // 移动端:单列
sm: 2, // 小屏2列
md: 2, // 中屏2列
lg: 3, // 大屏3列
xl: 4, // 超大屏4列
});
// 使用响应式列数或传入的列数
const actualColumnsPerRow = responsiveColumns || columnsPerRow;
// 将事件按 actualColumnsPerRow 个一组分成行
const rows = useMemo(() => {
const r = [];
for (let i = 0; i < events.length; i += columnsPerRow) {
r.push(events.slice(i, i + columnsPerRow));
for (let i = 0; i < events.length; i += actualColumnsPerRow) {
r.push(events.slice(i, i + actualColumnsPerRow));
}
return r;
}, [events, columnsPerRow]);
}, [events, actualColumnsPerRow]);
// 配置虚拟滚动器(纵向滚动 + 动态高度测量)
const rowVirtualizer = useVirtualizer({
@@ -301,17 +313,17 @@ const VirtualizedFourRowGrid = ({
w="100%"
transform={`translateY(${virtualRow.start}px)`}
>
{/* 使用 Grid 横向排列卡片(列数由 columnsPerRow 决定) */}
{/* 使用 Grid 横向排列卡片(列数由 actualColumnsPerRow 决定) */}
<Grid
templateColumns={`repeat(${columnsPerRow}, 1fr)`}
gap={columnsPerRow === 1 ? 3 : 4}
templateColumns={`repeat(${actualColumnsPerRow}, 1fr)`}
gap={actualColumnsPerRow === 1 ? 3 : 4}
w="100%"
>
{rowEvents.map((event, colIndex) => (
<Box key={event.id} w="100%" minW={0}>
<CardComponent
event={event}
index={virtualRow.index * columnsPerRow + colIndex}
index={virtualRow.index * actualColumnsPerRow + colIndex}
isFollowing={eventFollowStatus[event.id]?.isFollowing || false}
followerCount={eventFollowStatus[event.id]?.followerCount || event.follower_count || 0}
isSelected={selectedEvent?.id === event.id}

View File

@@ -8,6 +8,7 @@ import {
useColorModeValue,
} from '@chakra-ui/react';
import CollapsibleHeader from './CollapsibleHeader';
import { PROFESSIONAL_COLORS } from '../../../../constants/professionalTheme';
/**
* 通用可折叠区块组件
@@ -37,7 +38,7 @@ const CollapsibleSection = ({
showModeToggle = false,
defaultMode = 'detailed'
}) => {
const sectionBg = useColorModeValue('gray.50', 'gray.750');
const sectionBg = PROFESSIONAL_COLORS.background.secondary;
// 模式状态:'detailed' | 'simple'
const [displayMode, setDisplayMode] = useState(defaultMode);

View File

@@ -8,6 +8,7 @@ import {
Text,
useColorModeValue,
} from '@chakra-ui/react';
import { PROFESSIONAL_COLORS } from '../../../../constants/professionalTheme';
/**
* 事件描述区组件
@@ -15,9 +16,9 @@ import {
* @param {string} props.description - 事件描述文本
*/
const EventDescriptionSection = ({ description }) => {
const sectionBg = useColorModeValue('gray.50', 'gray.750');
const headingColor = useColorModeValue('gray.700', 'gray.200');
const textColor = useColorModeValue('gray.600', 'gray.400');
const sectionBg = PROFESSIONAL_COLORS.background.secondary;
const headingColor = PROFESSIONAL_COLORS.text.primary;
const textColor = PROFESSIONAL_COLORS.text.secondary;
// 如果没有描述,不渲染
if (!description) {