feat: 优化评论项组件的布局和交互,增强用户体验

This commit is contained in:
2025-09-10 11:45:17 +08:00
parent ff1d8b7928
commit 1d74723e44

View File

@ -149,106 +149,108 @@ export function CommentItem(
} }
return ( return (
<div className="flex"> <div>
<div className="fade-in"> <div className="flex">
{getGravatarByUser(comment.user)} <div onClick={() => clickToUserProfile(comment.user.username)} className="cursor-pointer fade-in">
</div> {getGravatarByUser(comment.user)}
<div className="flex-1 pl-2 fade-in-up"> </div>
<div className="font-bold text-base text-slate-800 dark:text-slate-100 fade-in-up">{comment.user.nickname}</div> <div className="flex-1 pl-2 fade-in-up">
<p className="text-lg text-slate-600 dark:text-slate-400 fade-in"> <div onClick={() => clickToUserProfile(comment.user.username)} className="font-bold text-base text-slate-800 dark:text-slate-100 cursor-pointer fade-in-up">{comment.user.nickname}</div>
{ <p className="text-lg text-slate-600 dark:text-slate-400 fade-in">
isPrivate && <Lock className="inline w-4 h-4 mr-1 mb-1 text-slate-500 dark:text-slate-400" /> {
} isPrivate && <Lock className="inline w-4 h-4 mr-1 mb-1 text-slate-500 dark:text-slate-400" />
{ }
parentComment && {
<>{t("reply")} <button onClick={() => clickToUserProfile(parentComment.user.nickname)} className="text-primary">{parentComment?.user.nickname}</button>: </> parentComment &&
} <>{t("reply")} <button onClick={() => clickToUserProfile(parentComment.user.nickname)} className="text-primary">{parentComment?.user.nickname}</button>: </>
{comment.content} }
</p> {comment.content}
<div className="mt-1 text-xs text-slate-500 dark:text-slate-400 flex items-center gap-4 fade-in"> </p>
<span>{new Date(comment.updatedAt).toLocaleString()}</span> <div className="mt-1 text-xs text-slate-500 dark:text-slate-400 flex items-center gap-4 fade-in">
{/* 点赞按钮 */} <span>{new Date(comment.updatedAt).toLocaleString()}</span>
<button {/* 点赞按钮 */}
title={t(liked ? "unlike" : "like")} <button
onClick={handleToggleLike} title={t(liked ? "unlike" : "like")}
className={`flex items-center justify-center px-2 py-1 h-5 gap-1 text-xs rounded onClick={handleToggleLike}
className={`flex items-center justify-center px-2 py-1 h-5 gap-1 text-xs rounded
${liked ? 'bg-primary ' : 'bg-slate-400 hover:bg-slate-600'} ${liked ? 'bg-primary ' : 'bg-slate-400 hover:bg-slate-600'}
text-primary-foreground dark:text-white dark:hover:bg-slate-500 fade-in`} text-primary-foreground dark:text-white dark:hover:bg-slate-500 fade-in`}
> >
<Heart className="w-3 h-3" /> <div>{likeCount}</div> <Heart className="w-3 h-3" /> <div>{likeCount}</div>
</button> </button>
{/* 回复按钮 */} {/* 回复按钮 */}
<button <button
title={t("reply")} title={t("reply")}
onClick={() => { setShowReplyInput(!showReplyInput); setShowEditInput(false); }} onClick={() => { setShowReplyInput(!showReplyInput); setShowEditInput(false); }}
className={`flex items-center justify-center px-2 py-1 h-5 className={`flex items-center justify-center px-2 py-1 h-5
text-primary-foreground dark:text-white text-xs text-primary-foreground dark:text-white text-xs
rounded ${showReplyInput ? "bg-slate-600" : "bg-slate-400"} hover:bg-slate-600 dark:hover:bg-slate-500 fade-in-up`}> rounded ${showReplyInput ? "bg-slate-600" : "bg-slate-400"} hover:bg-slate-600 dark:hover:bg-slate-500 fade-in-up`}>
<Reply className="w-3 h-3" /> <Reply className="w-3 h-3" />
</button> </button>
{/* 编辑和删除按钮 仅自己的评论可见 */} {/* 编辑和删除按钮 仅自己的评论可见 */}
{user?.id === comment.user.id && ( {user?.id === comment.user.id && (
<> <>
<button <button
title={t("edit")} title={t("edit")}
className={` className={`
flex items-center justify-center px-2 py-1 h-5 flex items-center justify-center px-2 py-1 h-5
text-primary-foreground dark:text-white text-xs text-primary-foreground dark:text-white text-xs
rounded ${showEditInput ? "bg-slate-600" : "bg-slate-400"} hover:bg-slate-600 dark:hover:bg-slate-500 fade-in-up`} rounded ${showEditInput ? "bg-slate-600" : "bg-slate-400"} hover:bg-slate-600 dark:hover:bg-slate-500 fade-in-up`}
onClick={() => { setShowEditInput(!showEditInput); setShowReplyInput(false); }} onClick={() => { setShowEditInput(!showEditInput); setShowReplyInput(false); }}
> >
<Pencil className="w-3 h-3" /> <Pencil className="w-3 h-3" />
</button> </button>
<button <button
title={t("delete")} title={t("delete")}
className={`flex items-center justify-center px-2 py-1 h-5 rounded className={`flex items-center justify-center px-2 py-1 h-5 rounded
text-primary-foreground dark:text-white text-xs text-primary-foreground dark:text-white text-xs
${confirming ? 'bg-red-600 hover:bg-red-700 dark:bg-red-500 dark:hover:bg-red-600' : 'bg-slate-400 hover:bg-slate-600 dark:hover:bg-slate-500'} fade-in`} ${confirming ? 'bg-red-600 hover:bg-red-700 dark:bg-red-500 dark:hover:bg-red-600' : 'bg-slate-400 hover:bg-slate-600 dark:hover:bg-slate-500'} fade-in`}
onClick={() => onClick(() => { onCommentDelete({ commentId: comment.id }); })} onClick={() => onClick(() => { onCommentDelete({ commentId: comment.id }); })}
onBlur={onBlur} onBlur={onBlur}
> >
<Trash className="w-3 h-3" /> <Trash className="w-3 h-3" />
{confirming && ( {confirming && (
<span className="ml-1 confirm-delete-anim">{t("confirm_delete")}</span> <span className="ml-1 confirm-delete-anim">{t("confirm_delete")}</span>
)} )}
</button>
</>
)}
{replyCount > 0 &&
<button onClick={toggleReplies} className="fade-in-up">
{!showReplies ? t("expand_replies", { count: replyCount }) : t("collapse_replies")}
</button> </button>
</> }
)}
{replyCount > 0 &&
<button onClick={toggleReplies} className="fade-in-up">
{!showReplies ? t("expand_replies", { count: replyCount }) : t("collapse_replies")}
</button>
}
</div>
{/* 这俩输入框一次只能显示一个 */}
{showReplyInput && !showEditInput && <CommentInput
user={user}
onCommentSubmitted={onReply}
/>}
{showEditInput && !showReplyInput && <CommentInput
user={user}
initContent={comment.content}
initIsPrivate={isPrivate}
onCommentSubmitted={onCommentEdit}
isUpdate={true}
/>}
{showReplies && replies.length > 0 && (
<div className="mt-4 pl-4 border-l border-slate-300 dark:border-slate-600 space-y-4">
{replies.map((reply) => (
<CommentItem
key={reply.id}
user={reply.user}
comment={reply}
parentComment={comment}
onCommentDelete={onReplyDelete}
/>
))}
</div> </div>
)} {/* 这俩输入框一次只能显示一个 */}
</div> {showReplyInput && !showEditInput && <CommentInput
</div > user={user}
onCommentSubmitted={onReply}
/>}
{showEditInput && !showReplyInput && <CommentInput
user={user}
initContent={comment.content}
initIsPrivate={isPrivate}
onCommentSubmitted={onCommentEdit}
isUpdate={true}
/>}
</div>
</div >
{showReplies && replies.length > 0 && (
<div className="mt-4 pl-4 md:pl-8 border-l border-slate-300 dark:border-slate-600 space-y-4">
{replies.map((reply) => (
<CommentItem
key={reply.id}
user={reply.user}
comment={reply}
parentComment={comment}
onCommentDelete={onReplyDelete}
/>
))}
</div>
)}</div>
) )
} }