- 新增访问统计:visitstats 服务与查询、visit_capture 中间件、爬虫/来源识别、管理端 analytics 页面 - 新增侧边栏:sidebar 服务与 handler、管理端 sidebar 配置页、前端侧边栏组件 - 新增 widget 嵌入代码生成(widgetCode)与 widgetApi - 遥测逻辑迁移至 handler 层,删除 service/telemetry - env 示例补充 Docker 部署可信代理 IP 说明
156 lines
4.7 KiB
TypeScript
156 lines
4.7 KiB
TypeScript
import type {
|
||
ActiveUser,
|
||
AnnouncementSummary,
|
||
Board,
|
||
BoardModerator,
|
||
BoardSidebarStats,
|
||
BoardWithCount,
|
||
CheckinStatus,
|
||
NewUser,
|
||
OverviewStats,
|
||
PostListItem,
|
||
PublicAdItem,
|
||
PublicSponsorItem,
|
||
SidebarPageItem,
|
||
User,
|
||
UserProfile,
|
||
} from "@/lib/api";
|
||
import PostToc, { type TocItem } from "@/components/PostToc";
|
||
import { WorkspaceNavPanel } from "@/components/home/WorkspaceNav";
|
||
import {
|
||
PulseCard,
|
||
Announcements,
|
||
AdsPanel,
|
||
SponsorsPanel,
|
||
HotRanking,
|
||
NewUsers,
|
||
ActiveUsers,
|
||
FriendLinks,
|
||
AboutSite,
|
||
} from "@/components/home/CommunityPanels";
|
||
import {
|
||
Moderators,
|
||
BoardIntro,
|
||
BoardPulse,
|
||
BoardHot,
|
||
BoardActive,
|
||
} from "@/components/home/BoardPanels";
|
||
import {
|
||
BoardCard as PostBoardCard,
|
||
AuthorRailCard as PostAuthorCard,
|
||
AuthorPosts as PostAuthorPosts,
|
||
} from "@/components/post/PostRailBlocks";
|
||
|
||
// 侧栏块 props 汇总:页面把已有数据整包传入,块按需取用;
|
||
// 某块所需数据缺失(如板块态没传 stats)时对应块渲染为空,安全跳过。
|
||
export interface SidebarBlockProps {
|
||
allowComments: boolean;
|
||
user?: User | null;
|
||
checkin?: CheckinStatus | null;
|
||
|
||
// home 范围
|
||
boards?: BoardWithCount[];
|
||
stats?: OverviewStats;
|
||
announcements?: AnnouncementSummary[];
|
||
canManageAnnouncements?: boolean;
|
||
ads?: PublicAdItem[];
|
||
adsPanelTitle?: string;
|
||
adsEnabled?: boolean;
|
||
sponsors?: PublicSponsorItem[];
|
||
sponsorsPanelTitle?: string;
|
||
sponsorsEnabled?: boolean;
|
||
hot?: PostListItem[];
|
||
newUsers?: NewUser[];
|
||
activeUsers?: ActiveUser[];
|
||
sidebarPages?: SidebarPageItem[];
|
||
siteDescription?: string;
|
||
canManagePages?: boolean;
|
||
|
||
// board 范围
|
||
board?: BoardWithCount;
|
||
moderators?: BoardModerator[];
|
||
boardStats?: BoardSidebarStats;
|
||
boardHot?: PostListItem[];
|
||
boardActiveUsers?: ActiveUser[];
|
||
|
||
// post 范围
|
||
postBoard?: Board;
|
||
authorProfile?: UserProfile;
|
||
authorPosts?: PostListItem[];
|
||
toc?: TocItem[];
|
||
}
|
||
|
||
// 内置块注册表:key → 组件。数据未就绪或未知 key 返回 null(渲染层静默跳过)。
|
||
export function renderSidebarBlock(key: string, p: SidebarBlockProps) {
|
||
switch (key) {
|
||
case "board_nav":
|
||
return p.boards ? <WorkspaceNavPanel boards={p.boards} user={p.user} /> : null;
|
||
case "pulse":
|
||
return p.stats ? (
|
||
<PulseCard stats={p.stats} checkin={p.checkin} allowComments={p.allowComments} />
|
||
) : null;
|
||
case "announcements":
|
||
return p.announcements ? (
|
||
<Announcements items={p.announcements} canManageAnnouncements={p.canManageAnnouncements} />
|
||
) : null;
|
||
case "ads":
|
||
return p.ads && p.adsEnabled !== false ? (
|
||
<AdsPanel items={p.ads} title={p.adsPanelTitle || "自助推广"} enabled />
|
||
) : null;
|
||
case "sponsors":
|
||
return p.sponsors && p.sponsorsEnabled !== false ? (
|
||
<SponsorsPanel
|
||
items={p.sponsors}
|
||
title={p.sponsorsPanelTitle || "赞助商"}
|
||
enabled
|
||
/>
|
||
) : null;
|
||
case "hot":
|
||
return p.hot ? <HotRanking posts={p.hot} allowComments={p.allowComments} /> : null;
|
||
case "new_users":
|
||
return p.newUsers ? <NewUsers users={p.newUsers} /> : null;
|
||
case "active_users":
|
||
return p.activeUsers ? (
|
||
<ActiveUsers users={p.activeUsers} allowComments={p.allowComments} />
|
||
) : null;
|
||
case "friend_links":
|
||
return <FriendLinks />;
|
||
case "about_site":
|
||
return p.sidebarPages || p.canManagePages ? (
|
||
<AboutSite
|
||
pages={p.sidebarPages ?? []}
|
||
siteDescription={p.siteDescription}
|
||
canManagePages={p.canManagePages}
|
||
/>
|
||
) : null;
|
||
case "board_moderators":
|
||
return p.moderators ? <Moderators items={p.moderators} /> : null;
|
||
case "board_intro":
|
||
return p.board ? <BoardIntro board={p.board} /> : null;
|
||
case "board_pulse":
|
||
return p.boardStats ? (
|
||
<BoardPulse stats={p.boardStats} checkin={p.checkin} allowComments={p.allowComments} />
|
||
) : null;
|
||
case "board_hot":
|
||
return p.boardHot ? (
|
||
<BoardHot posts={p.boardHot} allowComments={p.allowComments} />
|
||
) : null;
|
||
case "board_active":
|
||
return p.boardActiveUsers ? (
|
||
<BoardActive users={p.boardActiveUsers} allowComments={p.allowComments} />
|
||
) : null;
|
||
case "post_board":
|
||
return p.postBoard ? <PostBoardCard board={p.postBoard} /> : null;
|
||
case "post_author":
|
||
return p.authorProfile ? (
|
||
<PostAuthorCard profile={p.authorProfile} allowComments={p.allowComments} />
|
||
) : null;
|
||
case "post_author_posts":
|
||
return p.authorPosts ? <PostAuthorPosts posts={p.authorPosts} /> : null;
|
||
case "post_toc":
|
||
return p.toc && p.toc.length > 0 ? <PostToc items={p.toc} /> : null;
|
||
default:
|
||
return null;
|
||
}
|
||
}
|