feat: 增强评论功能,添加评论未更改提示,优化评论输入组件的占位符

This commit is contained in:
2025-09-10 11:59:42 +08:00
parent b380e971cc
commit 09c024ccbb
4 changed files with 39 additions and 14 deletions

View File

@ -49,6 +49,10 @@ export function CommentInput(
toast.error(t("content_required"));
return;
}
if (initContent === commentContent.trim() && initIsPrivate === isPrivate) {
toast.warning(t("comment_unchanged"));
return;
}
onCommentSubmitted({ commentContent, isPrivate });
setCommentContent("");
};
@ -62,7 +66,7 @@ export function CommentInput(
</div>
<div className="flex-1 pl-2 fade-in-up">
<Textarea
placeholder={user ? t("placeholder") : t("login_required", { loginButton: "登录" })}
placeholder={user ? (isPrivate ? t("private_placeholder") : t("placeholder")) : t("login_required", { loginButton: "登录" })}
className="w-full p-2 border border-gray-300 rounded-md fade-in-up"
value={commentContent}
onChange={(e) => setCommentContent(e.target.value)}
@ -77,7 +81,6 @@ export function CommentInput(
/>
<Label>{t("private")}</Label>
</div>
<button onClick={handleCommentSubmit} className="px-2 py-1 bg-blue-500 text-white rounded-md hover:bg-blue-600 transition-colors fade-in-up">
{isUpdate ? t("update") : t("submit")}
</button>

View File

@ -21,11 +21,15 @@ export function CommentItem(
comment,
parentComment,
onCommentDelete,
activeInput,
setActiveInputId
}: {
user: User | null,
comment: Comment,
parentComment: Comment | null,
onCommentDelete: ({ commentId }: { commentId: number }) => void,
activeInput: { id: number; type: 'reply' | 'edit' } | null,
setActiveInputId: (input: { id: number; type: 'reply' | 'edit' } | null) => void,
}
) {
const t = useTranslations("Comment")
@ -40,10 +44,8 @@ export function CommentItem(
const [isPrivate, setIsPrivate] = useState(comment.isPrivate);
const [replyCount, setReplyCount] = useState(comment.replyCount);
const [showReplies, setShowReplies] = useState(false);
const [showReplyInput, setShowReplyInput] = useState(false);
const [replies, setReplies] = useState<Comment[]>([]);
const [repliesLoaded, setRepliesLoaded] = useState(false);
const [showEditInput, setShowEditInput] = useState(false);
const handleToggleLike = () => {
if (!canClickLike) {
@ -112,7 +114,7 @@ export function CommentItem(
toast.success(t("edit_success"));
comment.content = newContent;
setIsPrivate(isPrivate);
setShowEditInput(false);
setActiveInputId(null);
}).catch(error => {
toast.error(t("edit_failed") + ": " + error.message);
});
@ -129,7 +131,7 @@ export function CommentItem(
toast.success(t("comment_success"));
reloadReplies();
setShowReplies(true);
setShowReplyInput(false);
setActiveInputId(null);
setReplyCount(replyCount + 1);
}).catch(error => {
toast.error(t("comment_failed") + ": " +
@ -181,10 +183,16 @@ export function CommentItem(
{/* 回复按钮 */}
<button
title={t("reply")}
onClick={() => { setShowReplyInput(!showReplyInput); setShowEditInput(false); }}
onClick={() => {
if (activeInput?.type === 'reply' && activeInput.id === comment.id) {
setActiveInputId(null);
} else {
setActiveInputId({ id: comment.id, type: 'reply' });
}
}}
className={`flex items-center justify-center px-2 py-1 h-5
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`}>
text-primary-foreground dark:text-white text-xs
rounded ${activeInput?.type === 'reply' && activeInput.id === comment.id ? "bg-slate-600" : "bg-slate-400"} hover:bg-slate-600 dark:hover:bg-slate-500 fade-in-up`}>
<Reply className="w-3 h-3" />
</button>
{/* 编辑和删除按钮 仅自己的评论可见 */}
@ -192,11 +200,18 @@ export function CommentItem(
<>
<button
title={t("edit")}
onClick={() => {
if (activeInput?.type === 'edit' && activeInput.id === comment.id) {
setActiveInputId(null);
} else {
setActiveInputId({ id: comment.id, type: 'edit' });
}
}}
className={`
flex items-center justify-center px-2 py-1 h-5
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`}
onClick={() => { setShowEditInput(!showEditInput); setShowReplyInput(false); }}
rounded ${activeInput?.type === 'edit' && activeInput.id === comment.id ? "bg-slate-600" : "bg-slate-400"} hover:bg-slate-600 dark:hover:bg-slate-500 fade-in-up`}
>
<Pencil className="w-3 h-3" />
</button>
@ -225,12 +240,12 @@ export function CommentItem(
}
</div>
{/* 这俩输入框一次只能显示一个 */}
{showReplyInput && !showEditInput && <CommentInput
{activeInput && activeInput.type === 'reply' && activeInput.id === comment.id && <CommentInput
user={user}
onCommentSubmitted={onReply}
initIsPrivate={isPrivate}
/>}
{showEditInput && !showReplyInput && <CommentInput
{activeInput && activeInput.type === 'edit' && activeInput.id === comment.id && <CommentInput
user={user}
initContent={comment.content}
initIsPrivate={isPrivate}
@ -249,6 +264,8 @@ export function CommentItem(
comment={reply}
parentComment={comment}
onCommentDelete={onReplyDelete}
activeInput={activeInput}
setActiveInputId={setActiveInputId}
/>
))}
</div>

View File

@ -33,6 +33,7 @@ export function CommentSection(
const [currentUser, setCurrentUser] = useState<User | null>(null);
const [comments, setComments] = useState<Comment[]>([]);
const [refreshCommentsKey, setRefreshCommentsKey] = useState(0);
const [activeInput, setActiveInput] = useState<{ id: number; type: 'reply' | 'edit' } | null>(null);
// 获取当前登录用户
useEffect(() => {
@ -98,6 +99,8 @@ export function CommentSection(
comment={comment}
parentComment={null}
onCommentDelete={onCommentDelete}
activeInput={activeInput}
setActiveInputId={setActiveInput}
/>
</div>
))}

View File

@ -7,6 +7,7 @@
"comment": "评论",
"comment_failed": "评论失败",
"comment_success": "评论成功!",
"comment_unchanged": "评论内容未更改。",
"confirm_delete": "确定吗?",
"content_required": "评论内容不能为空。",
"delete": "删除",
@ -20,8 +21,9 @@
"like_failed": "点赞失败",
"like_success": "点赞成功",
"login_required": "请先登录后再操作",
"placeholder": "写你的评论...",
"placeholder": "写你的评论...",
"private": "私密评论",
"private_placeholder": "悄悄地说一句...",
"reply": "回复",
"submit": "提交",
"unlike": "取消点赞",