feat: 评论管理操作收进更多菜单,减少管理员界面杂乱
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -18,7 +18,6 @@ import {
|
|||||||
AlertDialogFooter,
|
AlertDialogFooter,
|
||||||
AlertDialogHeader,
|
AlertDialogHeader,
|
||||||
AlertDialogTitle,
|
AlertDialogTitle,
|
||||||
AlertDialogTrigger,
|
|
||||||
} from '@/components/ui/alert-dialog';
|
} from '@/components/ui/alert-dialog';
|
||||||
import {
|
import {
|
||||||
Dialog,
|
Dialog,
|
||||||
@@ -32,6 +31,8 @@ import {
|
|||||||
DropdownMenu,
|
DropdownMenu,
|
||||||
DropdownMenuContent,
|
DropdownMenuContent,
|
||||||
DropdownMenuItem,
|
DropdownMenuItem,
|
||||||
|
DropdownMenuLabel,
|
||||||
|
DropdownMenuSeparator,
|
||||||
DropdownMenuTrigger,
|
DropdownMenuTrigger,
|
||||||
} from '@/components/ui/dropdown-menu';
|
} from '@/components/ui/dropdown-menu';
|
||||||
import { Button } from '@/components/ui/button';
|
import { Button } from '@/components/ui/button';
|
||||||
@@ -144,6 +145,11 @@ function CommentItem({
|
|||||||
&& !!onApprove;
|
&& !!onApprove;
|
||||||
const showEdited = !hidden && !!c.updated_at && isTimeDiffSignificant(c.created_at, c.updated_at);
|
const showEdited = !hidden && !!c.updated_at && isTimeDiffSignificant(c.created_at, c.updated_at);
|
||||||
const canReport = !hidden && !isEditing && !isCommentAuthor(c, currentUser);
|
const canReport = !hidden && !isEditing && !isCommentAuthor(c, currentUser);
|
||||||
|
const showHistory = isAdmin && showEdited;
|
||||||
|
const showManageMenu = !hidden && !isEditing && (
|
||||||
|
canApprove || canEdit || showHistory || canDelete || canReport
|
||||||
|
);
|
||||||
|
const showManageGroup = canApprove || canEdit || showHistory || canDelete;
|
||||||
const [editText, setEditText] = useState(c.content);
|
const [editText, setEditText] = useState(c.content);
|
||||||
const [saving, setSaving] = useState(false);
|
const [saving, setSaving] = useState(false);
|
||||||
const [deleting, setDeleting] = useState(false);
|
const [deleting, setDeleting] = useState(false);
|
||||||
@@ -152,6 +158,7 @@ function CommentItem({
|
|||||||
const [liked, setLiked] = useState(!!c.liked);
|
const [liked, setLiked] = useState(!!c.liked);
|
||||||
const [likeCount, setLikeCount] = useState(c.like_count ?? 0);
|
const [likeCount, setLikeCount] = useState(c.like_count ?? 0);
|
||||||
const [revOpen, setRevOpen] = useState(false);
|
const [revOpen, setRevOpen] = useState(false);
|
||||||
|
const [deleteOpen, setDeleteOpen] = useState(false);
|
||||||
const [reportOpen, setReportOpen] = useState(false);
|
const [reportOpen, setReportOpen] = useState(false);
|
||||||
const [reportReason, setReportReason] = useState<ReportReason>('spam');
|
const [reportReason, setReportReason] = useState<ReportReason>('spam');
|
||||||
const [reportDetail, setReportDetail] = useState('');
|
const [reportDetail, setReportDetail] = useState('');
|
||||||
@@ -333,24 +340,6 @@ function CommentItem({
|
|||||||
{c.reply_target && (
|
{c.reply_target && (
|
||||||
<span className="waline-reply-at">@{commentNick(c.reply_target)}</span>
|
<span className="waline-reply-at">@{commentNick(c.reply_target)}</span>
|
||||||
)}
|
)}
|
||||||
{!hidden && !isEditing && canApprove && (
|
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
className="waline-comment-reply-btn waline-comment-approve-btn"
|
|
||||||
disabled={approving}
|
|
||||||
onClick={async () => {
|
|
||||||
setApproving(true);
|
|
||||||
try {
|
|
||||||
await onApprove?.(c);
|
|
||||||
} finally {
|
|
||||||
setApproving(false);
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Check size={14} />
|
|
||||||
{approving ? '通过中…' : '通过'}
|
|
||||||
</button>
|
|
||||||
)}
|
|
||||||
{!hidden && !isEditing && !!renderReplyBox && (
|
{!hidden && !isEditing && !!renderReplyBox && (
|
||||||
isReplying ? (
|
isReplying ? (
|
||||||
<button type="button" className="waline-comment-reply-btn cancel" onClick={onCancelReply}>
|
<button type="button" className="waline-comment-reply-btn cancel" onClick={onCancelReply}>
|
||||||
@@ -366,12 +355,6 @@ function CommentItem({
|
|||||||
</Tooltip>
|
</Tooltip>
|
||||||
)
|
)
|
||||||
)}
|
)}
|
||||||
{!hidden && !isEditing && canEdit && (
|
|
||||||
<button type="button" className="waline-comment-reply-btn" onClick={() => onStartEdit(c)}>
|
|
||||||
<Pencil size={14} />
|
|
||||||
编辑
|
|
||||||
</button>
|
|
||||||
)}
|
|
||||||
{bountyAward?.open && bountyAward.canAward && c.user_id !== bountyAward.postAuthorId
|
{bountyAward?.open && bountyAward.canAward && c.user_id !== bountyAward.postAuthorId
|
||||||
&& c.status === 'published' && !hidden && (
|
&& c.status === 'published' && !hidden && (
|
||||||
<button
|
<button
|
||||||
@@ -383,46 +366,7 @@ function CommentItem({
|
|||||||
采纳
|
采纳
|
||||||
</button>
|
</button>
|
||||||
)}
|
)}
|
||||||
{!hidden && !isEditing && isAdmin && showEdited && (
|
{showManageMenu && (
|
||||||
<button type="button" className="waline-comment-reply-btn" onClick={() => setRevOpen(true)}>
|
|
||||||
<History size={14} />
|
|
||||||
编辑记录
|
|
||||||
</button>
|
|
||||||
)}
|
|
||||||
{!hidden && !isEditing && canDelete && (
|
|
||||||
<AlertDialog>
|
|
||||||
<AlertDialogTrigger asChild>
|
|
||||||
<button type="button" className="waline-comment-reply-btn cancel" disabled={deleting}>
|
|
||||||
<Trash2 size={14} />
|
|
||||||
删除
|
|
||||||
</button>
|
|
||||||
</AlertDialogTrigger>
|
|
||||||
<AlertDialogContent>
|
|
||||||
<AlertDialogHeader>
|
|
||||||
<AlertDialogTitle>确定删除该评论?</AlertDialogTitle>
|
|
||||||
<AlertDialogDescription>
|
|
||||||
将同时移入回收站其下所有回复,可在后台恢复或永久删除。
|
|
||||||
</AlertDialogDescription>
|
|
||||||
</AlertDialogHeader>
|
|
||||||
<AlertDialogFooter>
|
|
||||||
<AlertDialogCancel>取消</AlertDialogCancel>
|
|
||||||
<AlertDialogAction
|
|
||||||
onClick={async () => {
|
|
||||||
setDeleting(true);
|
|
||||||
try {
|
|
||||||
await onDelete(c);
|
|
||||||
} finally {
|
|
||||||
setDeleting(false);
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
删除
|
|
||||||
</AlertDialogAction>
|
|
||||||
</AlertDialogFooter>
|
|
||||||
</AlertDialogContent>
|
|
||||||
</AlertDialog>
|
|
||||||
)}
|
|
||||||
{canReport && (
|
|
||||||
<DropdownMenu>
|
<DropdownMenu>
|
||||||
<DropdownMenuTrigger asChild>
|
<DropdownMenuTrigger asChild>
|
||||||
<button
|
<button
|
||||||
@@ -433,19 +377,98 @@ function CommentItem({
|
|||||||
<MoreHorizontal size={14} />
|
<MoreHorizontal size={14} />
|
||||||
</button>
|
</button>
|
||||||
</DropdownMenuTrigger>
|
</DropdownMenuTrigger>
|
||||||
<DropdownMenuContent align="center" className="report-more-menu">
|
<DropdownMenuContent align="end" className="comment-manage-menu">
|
||||||
|
{showManageGroup && (
|
||||||
|
<>
|
||||||
|
<DropdownMenuLabel>管理</DropdownMenuLabel>
|
||||||
|
{canApprove && (
|
||||||
<DropdownMenuItem
|
<DropdownMenuItem
|
||||||
className="report-more-menu__item"
|
disabled={approving}
|
||||||
|
onSelect={() => {
|
||||||
|
void (async () => {
|
||||||
|
setApproving(true);
|
||||||
|
try {
|
||||||
|
await onApprove?.(c);
|
||||||
|
} finally {
|
||||||
|
setApproving(false);
|
||||||
|
}
|
||||||
|
})();
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Check size={14} aria-hidden />
|
||||||
|
{approving ? '通过中…' : '通过审核'}
|
||||||
|
</DropdownMenuItem>
|
||||||
|
)}
|
||||||
|
{canEdit && (
|
||||||
|
<DropdownMenuItem onSelect={() => onStartEdit(c)}>
|
||||||
|
<Pencil size={14} aria-hidden />
|
||||||
|
编辑
|
||||||
|
</DropdownMenuItem>
|
||||||
|
)}
|
||||||
|
{showHistory && (
|
||||||
|
<DropdownMenuItem onSelect={() => setRevOpen(true)}>
|
||||||
|
<History size={14} aria-hidden />
|
||||||
|
编辑记录
|
||||||
|
</DropdownMenuItem>
|
||||||
|
)}
|
||||||
|
{canDelete && (
|
||||||
|
<DropdownMenuItem
|
||||||
|
className="text-destructive focus:text-destructive"
|
||||||
|
disabled={deleting}
|
||||||
|
onSelect={() => setDeleteOpen(true)}
|
||||||
|
>
|
||||||
|
<Trash2 size={14} aria-hidden />
|
||||||
|
删除
|
||||||
|
</DropdownMenuItem>
|
||||||
|
)}
|
||||||
|
{canReport && <DropdownMenuSeparator />}
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
{canReport && (
|
||||||
|
<DropdownMenuItem
|
||||||
|
className="text-destructive focus:text-destructive"
|
||||||
onSelect={openReport}
|
onSelect={openReport}
|
||||||
>
|
>
|
||||||
<Flag size={14} />
|
<Flag size={14} aria-hidden />
|
||||||
举报
|
举报
|
||||||
</DropdownMenuItem>
|
</DropdownMenuItem>
|
||||||
|
)}
|
||||||
</DropdownMenuContent>
|
</DropdownMenuContent>
|
||||||
</DropdownMenu>
|
</DropdownMenu>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<AlertDialog open={deleteOpen} onOpenChange={setDeleteOpen}>
|
||||||
|
<AlertDialogContent>
|
||||||
|
<AlertDialogHeader>
|
||||||
|
<AlertDialogTitle>确定删除该评论?</AlertDialogTitle>
|
||||||
|
<AlertDialogDescription>
|
||||||
|
将同时移入回收站其下所有回复,可在后台恢复或永久删除。
|
||||||
|
</AlertDialogDescription>
|
||||||
|
</AlertDialogHeader>
|
||||||
|
<AlertDialogFooter>
|
||||||
|
<AlertDialogCancel disabled={deleting}>取消</AlertDialogCancel>
|
||||||
|
<AlertDialogAction
|
||||||
|
disabled={deleting}
|
||||||
|
onClick={(e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
void (async () => {
|
||||||
|
setDeleting(true);
|
||||||
|
try {
|
||||||
|
await onDelete(c);
|
||||||
|
setDeleteOpen(false);
|
||||||
|
} finally {
|
||||||
|
setDeleting(false);
|
||||||
|
}
|
||||||
|
})();
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
删除
|
||||||
|
</AlertDialogAction>
|
||||||
|
</AlertDialogFooter>
|
||||||
|
</AlertDialogContent>
|
||||||
|
</AlertDialog>
|
||||||
|
|
||||||
{isAdmin && (
|
{isAdmin && (
|
||||||
<CommentRevisionDialog open={revOpen} onOpenChange={setRevOpen} comment={c} />
|
<CommentRevisionDialog open={revOpen} onOpenChange={setRevOpen} comment={c} />
|
||||||
)}
|
)}
|
||||||
|
|||||||
@@ -5017,6 +5017,13 @@ a.post-title:visited {
|
|||||||
background: color-mix(in srgb, hsl(var(--destructive)) 10%, transparent);
|
background: color-mix(in srgb, hsl(var(--destructive)) 10%, transparent);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* 评论管理菜单(编辑 / 审核 / 删除 / 举报) */
|
||||||
|
.comment-manage-menu {
|
||||||
|
min-width: 9.5rem;
|
||||||
|
max-height: 70vh;
|
||||||
|
overflow-y: auto;
|
||||||
|
}
|
||||||
|
|
||||||
.report-more-menu__item svg {
|
.report-more-menu__item svg {
|
||||||
width: 14px;
|
width: 14px;
|
||||||
height: 14px;
|
height: 14px;
|
||||||
|
|||||||
Reference in New Issue
Block a user