feat: 全站评论开关,并统一后台表单控件
关闭评论后前台隐藏评论能力;外观/设置/公告改用 AdminField 与 Stepper。 Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -6,7 +6,6 @@ import Link from "next/link";
|
||||
import {
|
||||
Trash2,
|
||||
MessagesSquare,
|
||||
MessageSquareOff,
|
||||
ChevronRight,
|
||||
ChevronDown,
|
||||
BadgeCheck,
|
||||
@@ -31,7 +30,8 @@ import {
|
||||
} from "@/lib/api";
|
||||
import { canModerateBoard } from "@/lib/roles";
|
||||
import { toast } from "@/lib/toast";
|
||||
import { realtime, RT_SETTINGS_CHANGED, type RtSettingsData } from "@/lib/realtime";
|
||||
import { useAllowComments } from "@/components/CommentsPolicyProvider";
|
||||
import CommentsUnsupported from "@/components/CommentsUnsupported";
|
||||
import Avatar from "./Avatar";
|
||||
import Pagination from "./Pagination";
|
||||
import MarkdownBodyClient from "@/components/MarkdownBodyClient";
|
||||
@@ -57,8 +57,6 @@ interface CommentSectionProps {
|
||||
acceptedCommentId?: number;
|
||||
/** 抽奖已开奖:中奖楼层评论 ID(每名中奖者仅其最早主评一条) */
|
||||
winnerCommentIds?: number[];
|
||||
/** 全站是否开放评论;缺省 true。关闭时隐藏发评/回复入口 */
|
||||
allowComments?: boolean;
|
||||
}
|
||||
|
||||
// 递归统计子树回复数(彻底删除级联提示用)
|
||||
@@ -116,10 +114,10 @@ export default function CommentSection({
|
||||
acceptMode = null,
|
||||
acceptedCommentId = 0,
|
||||
winnerCommentIds = [],
|
||||
allowComments: allowCommentsProp = true,
|
||||
}: CommentSectionProps) {
|
||||
const winnerCommentIdSet = new Set(winnerCommentIds.filter((id) => id > 0));
|
||||
const router = useRouter();
|
||||
const commentsOpen = useAllowComments();
|
||||
const [content, setContent] = useState("");
|
||||
// 内联回复目标:在该评论下方就地发子评论(同一时间只有一个回复框)
|
||||
const [replyTarget, setReplyTarget] = useState<{ id: number; nickname: string } | null>(null);
|
||||
@@ -141,25 +139,14 @@ export default function CommentSection({
|
||||
const [historyCommentId, setHistoryCommentId] = useState<number | null>(null);
|
||||
// 折叠状态:哪些楼层展开了子回复(默认全部折叠,SSR 初始为收起)
|
||||
const [expandedFloors, setExpandedFloors] = useState<Set<number>>(new Set());
|
||||
const [commentsOpen, setCommentsOpen] = useState(allowCommentsProp !== false);
|
||||
const textareaRef = useRef<HTMLTextAreaElement>(null);
|
||||
|
||||
useEffect(() => {
|
||||
setCommentsOpen(allowCommentsProp !== false);
|
||||
}, [allowCommentsProp]);
|
||||
|
||||
// 管理后台开关变更后即时隐藏发评入口(后端仍硬拒绝)
|
||||
useEffect(() => {
|
||||
return realtime.on<RtSettingsData>(RT_SETTINGS_CHANGED, (data) => {
|
||||
if (typeof data?.allow_comments === "boolean") {
|
||||
setCommentsOpen(data.allow_comments);
|
||||
if (!data.allow_comments) {
|
||||
setReplyTarget(null);
|
||||
setReplyContent("");
|
||||
}
|
||||
}
|
||||
});
|
||||
}, []);
|
||||
if (!commentsOpen) {
|
||||
setReplyTarget(null);
|
||||
setReplyContent("");
|
||||
}
|
||||
}, [commentsOpen]);
|
||||
|
||||
const handleSubmit = async (e: React.FormEvent) => {
|
||||
e.preventDefault();
|
||||
@@ -1017,6 +1004,10 @@ export default function CommentSection({
|
||||
);
|
||||
};
|
||||
|
||||
if (!commentsOpen) {
|
||||
return <CommentsUnsupported />;
|
||||
}
|
||||
|
||||
return (
|
||||
<section className="panel p-6 sm:p-8 mt-6" aria-label="评论区">
|
||||
<div className="flex items-center gap-2.5 mb-6">
|
||||
@@ -1032,34 +1023,7 @@ export default function CommentSection({
|
||||
<span className="meta ml-auto text-[11.5px]">共 {totalPages} 页楼层</span>
|
||||
</div>
|
||||
|
||||
{!commentsOpen ? (
|
||||
<div
|
||||
className="mb-8 rounded-2xl border px-5 py-6 text-center sm:px-6"
|
||||
style={{
|
||||
borderColor: "color-mix(in srgb, var(--ink-3) 35%, var(--line))",
|
||||
background:
|
||||
"repeating-linear-gradient(-45deg, transparent, transparent 6px, color-mix(in srgb, var(--ink-3) 8%, transparent) 6px, color-mix(in srgb, var(--ink-3) 8%, transparent) 7px), var(--panel-2)",
|
||||
}}
|
||||
role="status"
|
||||
>
|
||||
<span
|
||||
className="mx-auto mb-3 flex h-11 w-11 items-center justify-center rounded-xl"
|
||||
style={{
|
||||
background: "color-mix(in srgb, var(--ink-3) 14%, transparent)",
|
||||
color: "var(--ink-3)",
|
||||
}}
|
||||
aria-hidden
|
||||
>
|
||||
<MessageSquareOff size={22} />
|
||||
</span>
|
||||
<p className="text-[15px] font-semibold" style={{ color: "var(--ink)" }}>
|
||||
评论功能暂时关闭
|
||||
</p>
|
||||
<p className="meta mt-1.5 text-[12.5px] leading-relaxed">
|
||||
站点当前暂停发表新评论与回复,历史评论仍可浏览。
|
||||
</p>
|
||||
</div>
|
||||
) : user ? (
|
||||
{user ? (
|
||||
<form onSubmit={handleSubmit} className="mb-8">
|
||||
<textarea
|
||||
ref={textareaRef}
|
||||
@@ -1106,9 +1070,7 @@ export default function CommentSection({
|
||||
<p className="text-sm" style={{ color: "var(--ink-2)" }}>
|
||||
暂无评论
|
||||
</p>
|
||||
<p className="meta text-[12.5px] mt-1">
|
||||
{commentsOpen ? "来说两句,抢占沙发" : "评论开放后即可参与讨论"}
|
||||
</p>
|
||||
<p className="meta text-[12.5px] mt-1">来说两句,抢占沙发</p>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user