mirror of
https://github.com/snowykami/neo-blog.git
synced 2025-09-26 19:16:24 +00:00
feat: 增强评论功能,添加评论未更改提示,优化评论输入组件的占位符
This commit is contained in:
@ -49,6 +49,10 @@ export function CommentInput(
|
|||||||
toast.error(t("content_required"));
|
toast.error(t("content_required"));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if (initContent === commentContent.trim() && initIsPrivate === isPrivate) {
|
||||||
|
toast.warning(t("comment_unchanged"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
onCommentSubmitted({ commentContent, isPrivate });
|
onCommentSubmitted({ commentContent, isPrivate });
|
||||||
setCommentContent("");
|
setCommentContent("");
|
||||||
};
|
};
|
||||||
@ -62,7 +66,7 @@ export function CommentInput(
|
|||||||
</div>
|
</div>
|
||||||
<div className="flex-1 pl-2 fade-in-up">
|
<div className="flex-1 pl-2 fade-in-up">
|
||||||
<Textarea
|
<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"
|
className="w-full p-2 border border-gray-300 rounded-md fade-in-up"
|
||||||
value={commentContent}
|
value={commentContent}
|
||||||
onChange={(e) => setCommentContent(e.target.value)}
|
onChange={(e) => setCommentContent(e.target.value)}
|
||||||
@ -77,7 +81,6 @@ export function CommentInput(
|
|||||||
/>
|
/>
|
||||||
<Label>{t("private")}</Label>
|
<Label>{t("private")}</Label>
|
||||||
</div>
|
</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">
|
<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")}
|
{isUpdate ? t("update") : t("submit")}
|
||||||
</button>
|
</button>
|
||||||
|
@ -21,11 +21,15 @@ export function CommentItem(
|
|||||||
comment,
|
comment,
|
||||||
parentComment,
|
parentComment,
|
||||||
onCommentDelete,
|
onCommentDelete,
|
||||||
|
activeInput,
|
||||||
|
setActiveInputId
|
||||||
}: {
|
}: {
|
||||||
user: User | null,
|
user: User | null,
|
||||||
comment: Comment,
|
comment: Comment,
|
||||||
parentComment: Comment | null,
|
parentComment: Comment | null,
|
||||||
onCommentDelete: ({ commentId }: { commentId: number }) => void,
|
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")
|
const t = useTranslations("Comment")
|
||||||
@ -40,10 +44,8 @@ export function CommentItem(
|
|||||||
const [isPrivate, setIsPrivate] = useState(comment.isPrivate);
|
const [isPrivate, setIsPrivate] = useState(comment.isPrivate);
|
||||||
const [replyCount, setReplyCount] = useState(comment.replyCount);
|
const [replyCount, setReplyCount] = useState(comment.replyCount);
|
||||||
const [showReplies, setShowReplies] = useState(false);
|
const [showReplies, setShowReplies] = useState(false);
|
||||||
const [showReplyInput, setShowReplyInput] = useState(false);
|
|
||||||
const [replies, setReplies] = useState<Comment[]>([]);
|
const [replies, setReplies] = useState<Comment[]>([]);
|
||||||
const [repliesLoaded, setRepliesLoaded] = useState(false);
|
const [repliesLoaded, setRepliesLoaded] = useState(false);
|
||||||
const [showEditInput, setShowEditInput] = useState(false);
|
|
||||||
|
|
||||||
const handleToggleLike = () => {
|
const handleToggleLike = () => {
|
||||||
if (!canClickLike) {
|
if (!canClickLike) {
|
||||||
@ -112,7 +114,7 @@ export function CommentItem(
|
|||||||
toast.success(t("edit_success"));
|
toast.success(t("edit_success"));
|
||||||
comment.content = newContent;
|
comment.content = newContent;
|
||||||
setIsPrivate(isPrivate);
|
setIsPrivate(isPrivate);
|
||||||
setShowEditInput(false);
|
setActiveInputId(null);
|
||||||
}).catch(error => {
|
}).catch(error => {
|
||||||
toast.error(t("edit_failed") + ": " + error.message);
|
toast.error(t("edit_failed") + ": " + error.message);
|
||||||
});
|
});
|
||||||
@ -129,7 +131,7 @@ export function CommentItem(
|
|||||||
toast.success(t("comment_success"));
|
toast.success(t("comment_success"));
|
||||||
reloadReplies();
|
reloadReplies();
|
||||||
setShowReplies(true);
|
setShowReplies(true);
|
||||||
setShowReplyInput(false);
|
setActiveInputId(null);
|
||||||
setReplyCount(replyCount + 1);
|
setReplyCount(replyCount + 1);
|
||||||
}).catch(error => {
|
}).catch(error => {
|
||||||
toast.error(t("comment_failed") + ": " +
|
toast.error(t("comment_failed") + ": " +
|
||||||
@ -181,10 +183,16 @@ export function CommentItem(
|
|||||||
{/* 回复按钮 */}
|
{/* 回复按钮 */}
|
||||||
<button
|
<button
|
||||||
title={t("reply")}
|
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
|
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 ${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" />
|
<Reply className="w-3 h-3" />
|
||||||
</button>
|
</button>
|
||||||
{/* 编辑和删除按钮 仅自己的评论可见 */}
|
{/* 编辑和删除按钮 仅自己的评论可见 */}
|
||||||
@ -192,11 +200,18 @@ export function CommentItem(
|
|||||||
<>
|
<>
|
||||||
<button
|
<button
|
||||||
title={t("edit")}
|
title={t("edit")}
|
||||||
|
onClick={() => {
|
||||||
|
if (activeInput?.type === 'edit' && activeInput.id === comment.id) {
|
||||||
|
setActiveInputId(null);
|
||||||
|
} else {
|
||||||
|
setActiveInputId({ id: comment.id, type: '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 ${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`}
|
||||||
onClick={() => { setShowEditInput(!showEditInput); setShowReplyInput(false); }}
|
|
||||||
>
|
>
|
||||||
<Pencil className="w-3 h-3" />
|
<Pencil className="w-3 h-3" />
|
||||||
</button>
|
</button>
|
||||||
@ -225,12 +240,12 @@ export function CommentItem(
|
|||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
{/* 这俩输入框一次只能显示一个 */}
|
{/* 这俩输入框一次只能显示一个 */}
|
||||||
{showReplyInput && !showEditInput && <CommentInput
|
{activeInput && activeInput.type === 'reply' && activeInput.id === comment.id && <CommentInput
|
||||||
user={user}
|
user={user}
|
||||||
onCommentSubmitted={onReply}
|
onCommentSubmitted={onReply}
|
||||||
initIsPrivate={isPrivate}
|
initIsPrivate={isPrivate}
|
||||||
/>}
|
/>}
|
||||||
{showEditInput && !showReplyInput && <CommentInput
|
{activeInput && activeInput.type === 'edit' && activeInput.id === comment.id && <CommentInput
|
||||||
user={user}
|
user={user}
|
||||||
initContent={comment.content}
|
initContent={comment.content}
|
||||||
initIsPrivate={isPrivate}
|
initIsPrivate={isPrivate}
|
||||||
@ -249,6 +264,8 @@ export function CommentItem(
|
|||||||
comment={reply}
|
comment={reply}
|
||||||
parentComment={comment}
|
parentComment={comment}
|
||||||
onCommentDelete={onReplyDelete}
|
onCommentDelete={onReplyDelete}
|
||||||
|
activeInput={activeInput}
|
||||||
|
setActiveInputId={setActiveInputId}
|
||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
|
@ -33,6 +33,7 @@ export function CommentSection(
|
|||||||
const [currentUser, setCurrentUser] = useState<User | null>(null);
|
const [currentUser, setCurrentUser] = useState<User | null>(null);
|
||||||
const [comments, setComments] = useState<Comment[]>([]);
|
const [comments, setComments] = useState<Comment[]>([]);
|
||||||
const [refreshCommentsKey, setRefreshCommentsKey] = useState(0);
|
const [refreshCommentsKey, setRefreshCommentsKey] = useState(0);
|
||||||
|
const [activeInput, setActiveInput] = useState<{ id: number; type: 'reply' | 'edit' } | null>(null);
|
||||||
|
|
||||||
// 获取当前登录用户
|
// 获取当前登录用户
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@ -98,6 +99,8 @@ export function CommentSection(
|
|||||||
comment={comment}
|
comment={comment}
|
||||||
parentComment={null}
|
parentComment={null}
|
||||||
onCommentDelete={onCommentDelete}
|
onCommentDelete={onCommentDelete}
|
||||||
|
activeInput={activeInput}
|
||||||
|
setActiveInputId={setActiveInput}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
))}
|
))}
|
||||||
|
@ -7,6 +7,7 @@
|
|||||||
"comment": "评论",
|
"comment": "评论",
|
||||||
"comment_failed": "评论失败",
|
"comment_failed": "评论失败",
|
||||||
"comment_success": "评论成功!",
|
"comment_success": "评论成功!",
|
||||||
|
"comment_unchanged": "评论内容未更改。",
|
||||||
"confirm_delete": "确定吗?",
|
"confirm_delete": "确定吗?",
|
||||||
"content_required": "评论内容不能为空。",
|
"content_required": "评论内容不能为空。",
|
||||||
"delete": "删除",
|
"delete": "删除",
|
||||||
@ -20,8 +21,9 @@
|
|||||||
"like_failed": "点赞失败",
|
"like_failed": "点赞失败",
|
||||||
"like_success": "点赞成功",
|
"like_success": "点赞成功",
|
||||||
"login_required": "请先登录后再操作",
|
"login_required": "请先登录后再操作",
|
||||||
"placeholder": "写你的评论...",
|
"placeholder": "写下你的评论...",
|
||||||
"private": "私密评论",
|
"private": "私密评论",
|
||||||
|
"private_placeholder": "悄悄地说一句...",
|
||||||
"reply": "回复",
|
"reply": "回复",
|
||||||
"submit": "提交",
|
"submit": "提交",
|
||||||
"unlike": "取消点赞",
|
"unlike": "取消点赞",
|
||||||
|
Reference in New Issue
Block a user