feat: 友链/书库/移动端导航/排行榜等多模块功能
新增模块: - 友链(friendlink)后端处理 + 前端管理页与友链板 - 书库(library):导入、章节、封面、阅读页、横竖版自适应 AdaptiveCoverSlot - 顶栏导航(header_nav)配置与 MobileTabBar/MobileRailDrawers 移动端抽屉 - 排行榜 service 测试、站点页面测试、时间线发布(timeline_release) 其它改动: - 后端 handlers/services 全量小幅调整 - 前端组件、库函数、URL/品牌/站点 URL 工具更新 - Lightbox 图片、MdEntries 条目卡、coverColor 派生色相等前端能力
This commit is contained in:
@@ -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>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user