公开页补齐自引用 Canonical 与按类型的结构化数据,图片补上说明文字。
后台设置和内容编辑改成可导航布局;部署用访客 origin 生成 Canonical,避免落到容器地址。 Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -15,7 +15,7 @@ import { siteDocumentTitle } from "@/lib/brand";
|
||||
import { isAdminOrAbove } from "@/lib/roles";
|
||||
import Pagination from "@/components/Pagination";
|
||||
import PostRow from "@/components/PostRow";
|
||||
import FeedTabs, { type FeedSort } from "@/components/home/FeedTabs";
|
||||
import FeedTabs from "@/components/home/FeedTabs";
|
||||
import FeedNewTip from "@/components/home/FeedNewTip";
|
||||
import { WorkspaceNav, WorkspaceNavMobile } from "@/components/home/WorkspaceNav";
|
||||
import { SiteDocBreadcrumb } from "@/components/site-doc";
|
||||
@@ -25,25 +25,24 @@ import {
|
||||
BoardPanelsMobile,
|
||||
BoardMissingPanel,
|
||||
} from "@/components/home/BoardPanels";
|
||||
|
||||
export async function generateMetadata(): Promise<Metadata> {
|
||||
const settings = await getPublicSettingsCached();
|
||||
return {
|
||||
title: { absolute: siteDocumentTitle(settings.site_name, settings.site_slogan) },
|
||||
description: settings.site_description,
|
||||
};
|
||||
}
|
||||
import { requestCanonical } from "@/lib/canonicalMeta";
|
||||
import { defaultFeedSort, homeCanonicalQuery, normalizeFeedSort } from "@/lib/siteUrl";
|
||||
import { listingJsonLd } from "@/lib/jsonLd";
|
||||
import JsonLd from "@/components/JsonLd";
|
||||
|
||||
interface HomePageProps {
|
||||
searchParams: Promise<{ q?: string; page?: string; sort?: string; board?: string }>;
|
||||
}
|
||||
|
||||
function normalizeSort(v: string | undefined, allowComments: boolean): FeedSort {
|
||||
if (v === "recommended") return "recommended";
|
||||
if (v === "new") return "new";
|
||||
if (!allowComments) return "new";
|
||||
if (v === "latest") return "latest";
|
||||
return "latest";
|
||||
export async function generateMetadata({ searchParams }: HomePageProps): Promise<Metadata> {
|
||||
const settings = await getPublicSettingsCached();
|
||||
const sp = await searchParams;
|
||||
const allowComments = settings.allow_comments !== false;
|
||||
return {
|
||||
title: { absolute: siteDocumentTitle(settings.site_name, settings.site_slogan) },
|
||||
description: settings.site_description,
|
||||
...(await requestCanonical("/", homeCanonicalQuery(sp, allowComments))),
|
||||
};
|
||||
}
|
||||
|
||||
// 空结果面板(无帖 / 无搜索结果)
|
||||
@@ -90,7 +89,7 @@ export default async function HomePage({ searchParams }: HomePageProps) {
|
||||
const cookie = authCookieHeader(await cookies());
|
||||
const publicSettings = await getPublicSettingsCached();
|
||||
const allowComments = publicSettings.allow_comments !== false;
|
||||
const sort = normalizeSort(sp.sort, allowComments);
|
||||
const sort = normalizeFeedSort(sp.sort, allowComments);
|
||||
// 与 layout 共享同一份 /me 请求(React cache 去重)
|
||||
const mePromise = getMeCached(cookie || undefined);
|
||||
const postsPromise = fetchPosts(
|
||||
@@ -125,10 +124,31 @@ export default async function HomePage({ searchParams }: HomePageProps) {
|
||||
// boardId 有效但接口失败 → 显示简卡;成功则板级右栏;否则全站右栏
|
||||
const boardPanelsMissing = showBoardPanels && !boardSidebar;
|
||||
|
||||
const pageName = isSearch
|
||||
? `搜索“${keyword}”`
|
||||
: activeBoard
|
||||
? activeBoard.name
|
||||
: sort === "new"
|
||||
? "最新发布"
|
||||
: sort === "recommended"
|
||||
? "推荐帖"
|
||||
: "最新讨论";
|
||||
const listingLd = listingJsonLd({
|
||||
siteName: publicSettings.site_name || "姜十三论坛",
|
||||
siteDescription: publicSettings.site_description,
|
||||
pageName,
|
||||
path: "/",
|
||||
query: homeCanonicalQuery(sp, allowComments),
|
||||
items: postsData.posts.map((p) => ({ id: p.id, name: p.title })),
|
||||
page,
|
||||
pageSize: 20,
|
||||
});
|
||||
|
||||
// 搜索态:单栏占满,无 Tabs/侧栏
|
||||
if (isSearch) {
|
||||
return (
|
||||
<div className="max-w-3xl mx-auto">
|
||||
<JsonLd data={listingLd} />
|
||||
<div className="mb-5">
|
||||
<h1 className="text-[24px] sm:text-[28px] font-extrabold tracking-tight" style={{ color: "var(--ink)" }}>
|
||||
搜索“<span style={{ color: "var(--accent)" }}>{keyword}</span>”
|
||||
@@ -149,27 +169,23 @@ export default async function HomePage({ searchParams }: HomePageProps) {
|
||||
page={page}
|
||||
size={20}
|
||||
basePath="/"
|
||||
query={{ q: keyword }}
|
||||
query={{
|
||||
q: keyword,
|
||||
...(sort !== defaultFeedSort(allowComments) ? { sort } : {}),
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
// 置顶帖直接按后端 pinned DESC 顺序并入统一信息流;标题仅供屏幕阅读器
|
||||
const heading = activeBoard
|
||||
? activeBoard.name
|
||||
: sort === "new"
|
||||
? "最新发布"
|
||||
: sort === "recommended"
|
||||
? "推荐帖"
|
||||
: "最新讨论";
|
||||
|
||||
const pageQuery: Record<string, string> = {};
|
||||
if (boardId > 0) pageQuery.board = String(boardId);
|
||||
if (sort !== "latest") pageQuery.sort = sort;
|
||||
if (sort !== defaultFeedSort(allowComments)) pageQuery.sort = sort;
|
||||
|
||||
return (
|
||||
<div>
|
||||
<JsonLd data={listingLd} />
|
||||
<WorkspaceNavMobile boards={boards} user={user} />
|
||||
|
||||
<div className={`flex items-start gap-6 xl:gap-7 ${activeBoard ? "" : "mt-5 lg:mt-0"}`}>
|
||||
@@ -177,7 +193,7 @@ export default async function HomePage({ searchParams }: HomePageProps) {
|
||||
|
||||
{/* 中栏:tab 栏与帖子流为同一个整体卡片(左栏切板块只替换这一列) */}
|
||||
<div className="flex-1 min-w-0">
|
||||
<h1 className="sr-only">{heading}</h1>
|
||||
<h1 className="sr-only">{pageName}</h1>
|
||||
|
||||
<div className="panel overflow-hidden">
|
||||
{activeBoard ? (
|
||||
|
||||
Reference in New Issue
Block a user