mirror of
https://github.com/snowykami/neo-blog.git
synced 2025-09-26 02:56:22 +00:00
feat: 增强评论功能,添加评论未更改提示,优化评论输入组件的占位符
This commit is contained in:
@ -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>
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
))}
|
||||
|
@ -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": "取消点赞",
|
||||
|
Reference in New Issue
Block a user