update ui
This commit is contained in:
@@ -2,10 +2,25 @@
|
|||||||
// 纵向分栏模式布局组件
|
// 纵向分栏模式布局组件
|
||||||
|
|
||||||
import React, { useState } from 'react';
|
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 { InfoIcon } from '@chakra-ui/icons';
|
||||||
import HorizontalDynamicNewsEventCard from '../EventCard/HorizontalDynamicNewsEventCard';
|
import HorizontalDynamicNewsEventCard from '../EventCard/HorizontalDynamicNewsEventCard';
|
||||||
import EventDetailScrollPanel from './EventDetailScrollPanel';
|
import EventDetailScrollPanel from './EventDetailScrollPanel';
|
||||||
|
import DynamicNewsDetailPanel from '../../DynamicNewsDetail/DynamicNewsDetailPanel';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 纵向分栏模式布局
|
* 纵向分栏模式布局
|
||||||
@@ -38,6 +53,20 @@ const VerticalModeLayout = ({
|
|||||||
const flexDirection = useBreakpointValue({ base: 'column', lg: 'row' });
|
const flexDirection = useBreakpointValue({ base: 'column', lg: 'row' });
|
||||||
const gap = useBreakpointValue({ base: 3, lg: 6 });
|
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)- 平衡布局,确保左侧有足够空间显示内容
|
// 固定布局比例:左侧(4),右侧(6)- 平衡布局,确保左侧有足够空间显示内容
|
||||||
const leftFlex = '4';
|
const leftFlex = '4';
|
||||||
const rightFlex = '6';
|
const rightFlex = '6';
|
||||||
@@ -89,7 +118,7 @@ const VerticalModeLayout = ({
|
|||||||
key={event.id}
|
key={event.id}
|
||||||
event={event}
|
event={event}
|
||||||
isSelected={selectedEvent?.id === event.id}
|
isSelected={selectedEvent?.id === event.id}
|
||||||
onEventClick={() => onEventSelect(event)}
|
onEventClick={() => handleMobileEventClick(event)}
|
||||||
isFollowing={eventFollowStatus[event.id]?.isFollowing}
|
isFollowing={eventFollowStatus[event.id]?.isFollowing}
|
||||||
followerCount={eventFollowStatus[event.id]?.followerCount}
|
followerCount={eventFollowStatus[event.id]?.followerCount}
|
||||||
onToggleFollow={onToggleFollow}
|
onToggleFollow={onToggleFollow}
|
||||||
@@ -133,6 +162,24 @@ const VerticalModeLayout = ({
|
|||||||
/>
|
/>
|
||||||
</Box>
|
</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>
|
</Flex>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
import React, { useRef, useMemo, useEffect } from 'react';
|
import React, { useRef, useMemo, useEffect } from 'react';
|
||||||
import { useVirtualizer } from '@tanstack/react-virtual';
|
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 { RepeatIcon } from '@chakra-ui/icons';
|
||||||
import { useColorModeValue } from '@chakra-ui/react';
|
import { useColorModeValue } from '@chakra-ui/react';
|
||||||
import DynamicNewsEventCard from '../EventCard/DynamicNewsEventCard';
|
import DynamicNewsEventCard from '../EventCard/DynamicNewsEventCard';
|
||||||
@@ -52,14 +52,26 @@ const VirtualizedFourRowGrid = ({
|
|||||||
const scrollbarThumbBg = useColorModeValue('#888', '#4A5568');
|
const scrollbarThumbBg = useColorModeValue('#888', '#4A5568');
|
||||||
const scrollbarThumbHoverBg = useColorModeValue('#555', '#718096');
|
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 rows = useMemo(() => {
|
||||||
const r = [];
|
const r = [];
|
||||||
for (let i = 0; i < events.length; i += columnsPerRow) {
|
for (let i = 0; i < events.length; i += actualColumnsPerRow) {
|
||||||
r.push(events.slice(i, i + columnsPerRow));
|
r.push(events.slice(i, i + actualColumnsPerRow));
|
||||||
}
|
}
|
||||||
return r;
|
return r;
|
||||||
}, [events, columnsPerRow]);
|
}, [events, actualColumnsPerRow]);
|
||||||
|
|
||||||
// 配置虚拟滚动器(纵向滚动 + 动态高度测量)
|
// 配置虚拟滚动器(纵向滚动 + 动态高度测量)
|
||||||
const rowVirtualizer = useVirtualizer({
|
const rowVirtualizer = useVirtualizer({
|
||||||
@@ -301,17 +313,17 @@ const VirtualizedFourRowGrid = ({
|
|||||||
w="100%"
|
w="100%"
|
||||||
transform={`translateY(${virtualRow.start}px)`}
|
transform={`translateY(${virtualRow.start}px)`}
|
||||||
>
|
>
|
||||||
{/* 使用 Grid 横向排列卡片(列数由 columnsPerRow 决定) */}
|
{/* 使用 Grid 横向排列卡片(列数由 actualColumnsPerRow 决定) */}
|
||||||
<Grid
|
<Grid
|
||||||
templateColumns={`repeat(${columnsPerRow}, 1fr)`}
|
templateColumns={`repeat(${actualColumnsPerRow}, 1fr)`}
|
||||||
gap={columnsPerRow === 1 ? 3 : 4}
|
gap={actualColumnsPerRow === 1 ? 3 : 4}
|
||||||
w="100%"
|
w="100%"
|
||||||
>
|
>
|
||||||
{rowEvents.map((event, colIndex) => (
|
{rowEvents.map((event, colIndex) => (
|
||||||
<Box key={event.id} w="100%" minW={0}>
|
<Box key={event.id} w="100%" minW={0}>
|
||||||
<CardComponent
|
<CardComponent
|
||||||
event={event}
|
event={event}
|
||||||
index={virtualRow.index * columnsPerRow + colIndex}
|
index={virtualRow.index * actualColumnsPerRow + colIndex}
|
||||||
isFollowing={eventFollowStatus[event.id]?.isFollowing || false}
|
isFollowing={eventFollowStatus[event.id]?.isFollowing || false}
|
||||||
followerCount={eventFollowStatus[event.id]?.followerCount || event.follower_count || 0}
|
followerCount={eventFollowStatus[event.id]?.followerCount || event.follower_count || 0}
|
||||||
isSelected={selectedEvent?.id === event.id}
|
isSelected={selectedEvent?.id === event.id}
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import {
|
|||||||
useColorModeValue,
|
useColorModeValue,
|
||||||
} from '@chakra-ui/react';
|
} from '@chakra-ui/react';
|
||||||
import CollapsibleHeader from './CollapsibleHeader';
|
import CollapsibleHeader from './CollapsibleHeader';
|
||||||
|
import { PROFESSIONAL_COLORS } from '../../../../constants/professionalTheme';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 通用可折叠区块组件
|
* 通用可折叠区块组件
|
||||||
@@ -37,7 +38,7 @@ const CollapsibleSection = ({
|
|||||||
showModeToggle = false,
|
showModeToggle = false,
|
||||||
defaultMode = 'detailed'
|
defaultMode = 'detailed'
|
||||||
}) => {
|
}) => {
|
||||||
const sectionBg = useColorModeValue('gray.50', 'gray.750');
|
const sectionBg = PROFESSIONAL_COLORS.background.secondary;
|
||||||
|
|
||||||
// 模式状态:'detailed' | 'simple'
|
// 模式状态:'detailed' | 'simple'
|
||||||
const [displayMode, setDisplayMode] = useState(defaultMode);
|
const [displayMode, setDisplayMode] = useState(defaultMode);
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import {
|
|||||||
Text,
|
Text,
|
||||||
useColorModeValue,
|
useColorModeValue,
|
||||||
} from '@chakra-ui/react';
|
} from '@chakra-ui/react';
|
||||||
|
import { PROFESSIONAL_COLORS } from '../../../../constants/professionalTheme';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 事件描述区组件
|
* 事件描述区组件
|
||||||
@@ -15,9 +16,9 @@ import {
|
|||||||
* @param {string} props.description - 事件描述文本
|
* @param {string} props.description - 事件描述文本
|
||||||
*/
|
*/
|
||||||
const EventDescriptionSection = ({ description }) => {
|
const EventDescriptionSection = ({ description }) => {
|
||||||
const sectionBg = useColorModeValue('gray.50', 'gray.750');
|
const sectionBg = PROFESSIONAL_COLORS.background.secondary;
|
||||||
const headingColor = useColorModeValue('gray.700', 'gray.200');
|
const headingColor = PROFESSIONAL_COLORS.text.primary;
|
||||||
const textColor = useColorModeValue('gray.600', 'gray.400');
|
const textColor = PROFESSIONAL_COLORS.text.secondary;
|
||||||
|
|
||||||
// 如果没有描述,不渲染
|
// 如果没有描述,不渲染
|
||||||
if (!description) {
|
if (!description) {
|
||||||
|
|||||||
Reference in New Issue
Block a user