feat: 添加评论、反应、离线编辑及主题定制功能
All checks were successful
test/timeline-frontend/pipeline/head This commit looks good
All checks were successful
test/timeline-frontend/pipeline/head This commit looks good
- 实现评论系统,包括评论输入、列表展示和集成指南 - 添加反应功能组件(ReactionBar、ReactionButton、ReactionPicker) - 实现离线编辑支持,包括同步状态管理和冲突解决 - 添加主题定制功能,支持多种配色方案和主题预览 - 新增多视图布局选项(时间线、分组、砌体视图) - 实现个人资料编辑器,支持头像、简介和自定义字段编辑 - 添加统计页面,展示存储使用情况和上传趋势 - 新增相册管理功能,支持相册创建、编辑和照片管理 - 实现响应式设计和加载骨架屏组件 - 扩展国际化支持,新增孟加拉语、波斯语、印尼语、日语、葡萄牙语等语言 - 添加错误边界组件和离线指示器 - 更新配置文件、路由和依赖项 - 新增完整的文档、测试用例和集成指南
This commit is contained in:
129
src/components/Comments/CommentList.tsx
Normal file
129
src/components/Comments/CommentList.tsx
Normal file
@@ -0,0 +1,129 @@
|
||||
/**
|
||||
* CommentList Component
|
||||
* Feature: personal-user-enhancements
|
||||
*
|
||||
* Displays a list of comments with virtualization for long lists
|
||||
*/
|
||||
|
||||
import React, { useMemo } from 'react';
|
||||
import { Empty, Divider, Spin } from 'antd';
|
||||
import { FixedSizeList as List } from 'react-window';
|
||||
import CommentItem from './CommentItem';
|
||||
|
||||
export interface CommentListProps {
|
||||
/** Array of comments to display */
|
||||
comments: API.Comment[];
|
||||
/** Loading state */
|
||||
loading?: boolean;
|
||||
/** Callback when comment is edited */
|
||||
onEdit?: (id: string, text: string) => void | Promise<void>;
|
||||
/** Callback when comment is deleted */
|
||||
onDelete?: (id: string) => void | Promise<void>;
|
||||
/** Loading state for edit operation */
|
||||
editLoading?: boolean;
|
||||
/** Loading state for delete operation */
|
||||
deleteLoading?: boolean;
|
||||
/** Enable virtualization (default: true for >20 comments) */
|
||||
enableVirtualization?: boolean;
|
||||
/** Height of the list container (for virtualization) */
|
||||
height?: number;
|
||||
/** Item height estimate (for virtualization) */
|
||||
itemHeight?: number;
|
||||
}
|
||||
|
||||
const VIRTUALIZATION_THRESHOLD = 20;
|
||||
const DEFAULT_ITEM_HEIGHT = 100;
|
||||
const DEFAULT_LIST_HEIGHT = 600;
|
||||
|
||||
const CommentList: React.FC<CommentListProps> = ({
|
||||
comments,
|
||||
loading = false,
|
||||
onEdit,
|
||||
onDelete,
|
||||
editLoading = false,
|
||||
deleteLoading = false,
|
||||
enableVirtualization,
|
||||
height = DEFAULT_LIST_HEIGHT,
|
||||
itemHeight = DEFAULT_ITEM_HEIGHT,
|
||||
}) => {
|
||||
// Sort comments chronologically (oldest first)
|
||||
const sortedComments = useMemo(() => {
|
||||
return [...comments].sort((a, b) => {
|
||||
return new Date(a.createdAt).getTime() - new Date(b.createdAt).getTime();
|
||||
});
|
||||
}, [comments]);
|
||||
|
||||
// Determine if virtualization should be used
|
||||
const shouldVirtualize = useMemo(() => {
|
||||
if (enableVirtualization !== undefined) {
|
||||
return enableVirtualization;
|
||||
}
|
||||
return sortedComments.length > VIRTUALIZATION_THRESHOLD;
|
||||
}, [enableVirtualization, sortedComments.length]);
|
||||
|
||||
// Show loading state
|
||||
if (loading) {
|
||||
return (
|
||||
<div style={{ textAlign: 'center', padding: '40px 0' }}>
|
||||
<Spin size="large" />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
// Show empty state
|
||||
if (sortedComments.length === 0) {
|
||||
return (
|
||||
<Empty
|
||||
description="No comments yet"
|
||||
style={{ padding: '40px 0' }}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
// Render a single comment item
|
||||
const renderCommentItem = (comment: API.Comment, index: number) => (
|
||||
<div key={comment.id}>
|
||||
<CommentItem
|
||||
comment={comment}
|
||||
onEdit={onEdit}
|
||||
onDelete={onDelete}
|
||||
editLoading={editLoading}
|
||||
deleteLoading={deleteLoading}
|
||||
/>
|
||||
{index < sortedComments.length - 1 && <Divider style={{ margin: '8px 0' }} />}
|
||||
</div>
|
||||
);
|
||||
|
||||
// Render with virtualization for long lists
|
||||
if (shouldVirtualize) {
|
||||
const Row = ({ index, style }: { index: number; style: React.CSSProperties }) => {
|
||||
const comment = sortedComments[index];
|
||||
return (
|
||||
<div style={style}>
|
||||
{renderCommentItem(comment, index)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
<List
|
||||
height={height}
|
||||
itemCount={sortedComments.length}
|
||||
itemSize={itemHeight}
|
||||
width="100%"
|
||||
overscanCount={5}
|
||||
>
|
||||
{Row}
|
||||
</List>
|
||||
);
|
||||
}
|
||||
|
||||
// Render without virtualization for short lists
|
||||
return (
|
||||
<div>
|
||||
{sortedComments.map((comment, index) => renderCommentItem(comment, index))}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default CommentList;
|
||||
Reference in New Issue
Block a user