feat: 全站评论开关,并统一后台表单控件

关闭评论后前台隐藏评论能力;外观/设置/公告改用 AdminField 与 Stepper。

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-09-17 01:22:00 +08:00
parent 442af625f6
commit d93635c961
27 changed files with 989 additions and 479 deletions

View File

@@ -27,7 +27,15 @@ import { formatCompact, formatShortDate } from "@/lib/format";
/* ---------- 站点数据(2×2 bento 统计瓦片) ---------- */
function PulseCard({ stats, checkin }: { stats: OverviewStats; checkin?: CheckinStatus | null }) {
function PulseCard({
stats,
checkin,
allowComments,
}: {
stats: OverviewStats;
checkin?: CheckinStatus | null;
allowComments: boolean;
}) {
const cells = [
{
icon: <Users size={12.5} />,
@@ -43,13 +51,25 @@ function PulseCard({ stats, checkin }: { stats: OverviewStats; checkin?: Checkin
foot: `+${formatCompact(stats.today_posts)} 今日`,
up: true,
},
{
icon: <MessageCircle size={12.5} />,
label: "回复总数",
value: formatCompact(stats.comments),
foot: `+${formatCompact(stats.today_comments)} 今日`,
up: true,
},
...(allowComments
? [
{
icon: <MessageCircle size={12.5} />,
label: "回复总数",
value: formatCompact(stats.comments),
foot: `+${formatCompact(stats.today_comments)} 今日`,
up: true,
},
]
: [
{
icon: <TrendingUp size={12.5} />,
label: "今日新帖",
value: formatCompact(stats.today_posts),
foot: "本日新增",
up: stats.today_posts > 0,
},
]),
{
icon: <Activity size={12.5} />,
label: "在线用户",
@@ -138,7 +158,7 @@ function Announcements({ items }: { items: AnnouncementSummary[] }) {
/* ---------- 热门榜 ---------- */
function HotRanking({ posts }: { posts: PostListItem[] }) {
function HotRanking({ posts, allowComments }: { posts: PostListItem[]; allowComments: boolean }) {
return (
<section className="j13-module" aria-label="热门讨论">
<p className="j13-module-title mb-1.5">
@@ -157,9 +177,11 @@ function HotRanking({ posts }: { posts: PostListItem[] }) {
{p.title}
</span>
<span className="mt-1 flex items-center gap-2.5 meta text-[11.5px]">
<span className="inline-flex items-center gap-1">
<MessageCircle size={11.5} /> {p.comment_count}
</span>
{allowComments ? (
<span className="inline-flex items-center gap-1">
<MessageCircle size={11.5} /> {p.comment_count}
</span>
) : null}
<span className="inline-flex items-center gap-1">
<Heart size={11.5} /> {p.like_count}
</span>
@@ -211,7 +233,7 @@ function NewUsers({ users }: { users: NewUser[] }) {
/* ---------- 活跃成员(本周发帖 / 回复) ---------- */
function ActiveUsers({ users }: { users: ActiveUser[] }) {
function ActiveUsers({ users, allowComments }: { users: ActiveUser[]; allowComments: boolean }) {
return (
<section className="j13-module" aria-label="本周活跃成员">
<p className="j13-module-title mb-2">
@@ -241,17 +263,23 @@ function ActiveUsers({ users }: { users: ActiveUser[] }) {
<span className="inline-flex items-center gap-1">
<PenLine size={10.5} /> 发帖 {u.post_count}
</span>
<span className="inline-flex items-center gap-1">
<MessageCircle size={10.5} /> 回复 {u.comment_count}
</span>
{allowComments ? (
<span className="inline-flex items-center gap-1">
<MessageCircle size={10.5} /> 回复 {u.comment_count}
</span>
) : null}
</span>
</span>
<span
className="shrink-0 text-[13px] tabular-nums"
style={{ color: "var(--accent)" }}
aria-label={`本周共 ${u.post_count + u.comment_count} 次互动`}
aria-label={
allowComments
? `本周共 ${u.post_count + u.comment_count} 次互动`
: `本周发帖 ${u.post_count}`
}
>
{u.post_count + u.comment_count}
{allowComments ? u.post_count + u.comment_count : u.post_count}
</span>
</Link>
</li>
@@ -309,46 +337,44 @@ type PanelsProps = {
announcements: AnnouncementSummary[];
newUsers: NewUser[];
checkin?: CheckinStatus | null;
allowComments: boolean;
};
export function CommunityPanels({
function CommunityPanelsBody({
stats,
hot,
activeUsers,
announcements,
newUsers,
checkin,
allowComments,
}: PanelsProps) {
return (
<>
<PulseCard stats={stats} checkin={checkin} allowComments={allowComments} />
<Announcements items={announcements} />
<HotRanking posts={hot} allowComments={allowComments} />
<NewUsers users={newUsers} />
<ActiveUsers users={activeUsers} allowComments={allowComments} />
<FriendLinks />
</>
);
}
export function CommunityPanels(props: PanelsProps) {
return (
<aside className="hidden w-[280px] shrink-0 lg:block xl:w-[300px]" aria-label="社区面板">
<div className="sticky top-24 space-y-4">
<PulseCard stats={stats} checkin={checkin} />
<Announcements items={announcements} />
<HotRanking posts={hot} />
<NewUsers users={newUsers} />
<ActiveUsers users={activeUsers} />
<FriendLinks />
<CommunityPanelsBody {...props} />
</div>
</aside>
);
}
export function CommunityPanelsMobile({
stats,
hot,
activeUsers,
announcements,
newUsers,
checkin,
}: PanelsProps) {
export function CommunityPanelsMobile(props: PanelsProps) {
return (
<div className="space-y-4 lg:hidden" aria-label="社区面板">
<PulseCard stats={stats} checkin={checkin} />
<Announcements items={announcements} />
<HotRanking posts={hot} />
<NewUsers users={newUsers} />
<ActiveUsers users={activeUsers} />
<FriendLinks />
<CommunityPanelsBody {...props} />
</div>
);
}