feat: 友链/书库/移动端导航/排行榜等多模块功能

新增模块:
- 友链(friendlink)后端处理 + 前端管理页与友链板
- 书库(library):导入、章节、封面、阅读页、横竖版自适应 AdaptiveCoverSlot
- 顶栏导航(header_nav)配置与 MobileTabBar/MobileRailDrawers 移动端抽屉
- 排行榜 service 测试、站点页面测试、时间线发布(timeline_release)

其它改动:
- 后端 handlers/services 全量小幅调整
- 前端组件、库函数、URL/品牌/站点 URL 工具更新
- Lightbox 图片、MdEntries 条目卡、coverColor 派生色相等前端能力
This commit is contained in:
2026-09-30 16:30:07 +08:00
parent e487bc2e92
commit 4f3f3a265c
105 changed files with 12371 additions and 852 deletions

View File

@@ -7,6 +7,8 @@ import {
fetchOverview,
fetchBoardSidebar,
fetchSidebar,
fetchFriendLinks,
type FriendLink,
type OverviewResponse,
type BoardSidebarResponse,
type SidebarPublicPayload,
@@ -109,13 +111,18 @@ export default async function HomePage({ searchParams }: HomePageProps) {
const sidebarPromise: Promise<SidebarPublicPayload | null> = isSearch
? Promise.resolve(null)
: fetchSidebar(cookie).catch(() => null);
// 友情链接列表失败不阻塞页面
const friendLinksPromise: Promise<{ links: FriendLink[] } | null> = isSearch
? Promise.resolve(null)
: fetchFriendLinks(cookie).catch(() => null);
const [me, postsData, overview, boardSidebar, sidebarData] = await Promise.all([
const [me, postsData, overview, boardSidebar, sidebarData, friendLinksData] = await Promise.all([
mePromise,
postsPromise,
overviewPromise,
boardSidebarPromise,
sidebarPromise,
friendLinksPromise,
]);
const sidebar = sidebarData ?? { config: defaultSidebarConfig(), widgets: [] };
const user = me.user;
@@ -142,6 +149,8 @@ export default async function HomePage({ searchParams }: HomePageProps) {
user,
boards,
checkin: (boardSidebar ?? overview)?.checkin ?? undefined,
// 友链列表独立于 overview:即使聚合接口失败也保留「申请」入口
friendLinks: friendLinksData?.links ?? [],
...(overview
? {
stats: overview.stats,
@@ -171,11 +180,6 @@ export default async function HomePage({ searchParams }: HomePageProps) {
}
: {}),
};
// 窄屏堆叠:右栏列表 + 左栏列表(板块目录已在顶部有横向板块条,跳过)
const mobileBlocks = [
...scopeLists.right,
...scopeLists.left.filter((r) => r.key !== "board_nav"),
];
const pageName = isSearch
? `搜索“${keyword}”`
@@ -240,7 +244,31 @@ export default async function HomePage({ searchParams }: HomePageProps) {
return (
<div className="j13-fluid-home">
<JsonLd data={listingLd} />
<WorkspaceNavMobile boards={boards} />
{/* 移动端:顶部横向板块条 = 左右抽屉的触发行——
☰ 打开左抽屉(桌面左栏:板块目录 + 工作台),▦ 打开右抽屉(桌面右栏面板) */}
<WorkspaceNavMobile
boards={boards}
left={
scopeLists.left.length > 0 ? (
<SidebarRenderer
blocks={scopeLists.left}
widgets={sidebar.widgets}
props={sidebarProps}
className="space-y-4"
/>
) : undefined
}
right={
scopeLists.right.length > 0 ? (
<SidebarRenderer
blocks={scopeLists.right}
widgets={sidebar.widgets}
props={sidebarProps}
className="space-y-4"
/>
) : undefined
}
/>
<div className={`flex items-start gap-6 xl:gap-7 flex-1 ${activeBoard ? "" : "lg:mt-0"}`}>
{/* 左栏:按配置渲染(缺省 = 板块目录) */}
@@ -326,17 +354,6 @@ export default async function HomePage({ searchParams }: HomePageProps) {
</aside>
) : null}
</div>
{/* 窄屏:面板下沉到帖子流之后(右栏列表 + 左栏列表,板块目录除外) */}
{mobileBlocks.length > 0 && (
<div className="j13-flat-rail mt-3 lg:hidden">
<SidebarRenderer
blocks={mobileBlocks}
widgets={sidebar.widgets}
props={sidebarProps}
/>
</div>
)}
</div>
);
}