公开页补齐自引用 Canonical 与按类型的结构化数据,图片补上说明文字。
后台设置和内容编辑改成可导航布局;部署用访客 origin 生成 Canonical,避免落到容器地址。 Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -20,6 +20,10 @@ import RoleBadge from "@/components/RoleBadge";
|
||||
import { roleMeta } from "@/lib/roles";
|
||||
import StartDMButton from "./StartDMButton";
|
||||
import StaffUserMenu from "@/components/StaffUserMenu";
|
||||
import { requestCanonical } from "@/lib/canonicalMeta";
|
||||
import { absoluteCanonical, canonicalPage } from "@/lib/siteUrl";
|
||||
import { profileJsonLd } from "@/lib/jsonLd";
|
||||
import JsonLd from "@/components/JsonLd";
|
||||
|
||||
interface UserPageProps {
|
||||
params: Promise<{ id: string }>;
|
||||
@@ -28,16 +32,33 @@ interface UserPageProps {
|
||||
|
||||
export type UserTab = "posts" | "comments" | "settings" | "security";
|
||||
|
||||
export async function generateMetadata({ params }: UserPageProps): Promise<Metadata> {
|
||||
export async function generateMetadata({ params, searchParams }: UserPageProps): Promise<Metadata> {
|
||||
const { id } = await params;
|
||||
const sp = await searchParams;
|
||||
const rawTab = sp.tab;
|
||||
const tab: UserTab =
|
||||
rawTab === "comments" ? "comments" :
|
||||
rawTab === "settings" ? "settings" :
|
||||
rawTab === "security" ? "security" : "posts";
|
||||
try {
|
||||
const data = await fetchUserProfile(id, 1);
|
||||
const allowComments = (await getPublicSettingsCached()).allow_comments !== false;
|
||||
const title = data.user.nickname || data.user.username;
|
||||
const description = allowComments
|
||||
? `查看 ${data.user.nickname} 的资料、发帖与评论`
|
||||
: `查看 ${data.user.nickname} 的资料与发帖`;
|
||||
// 资料/安全 tab 仅本人可见,不声明 Canonical,避免被当成公开资料页或继承首页
|
||||
if (tab === "settings" || tab === "security") {
|
||||
return { title, description };
|
||||
}
|
||||
const query: Record<string, string | number> = {};
|
||||
if (allowComments && tab === "comments") query.tab = "comments";
|
||||
const page = canonicalPage(sp.page);
|
||||
if (page) query.page = page;
|
||||
return {
|
||||
title: data.user.nickname || data.user.username,
|
||||
description: allowComments
|
||||
? `查看 ${data.user.nickname} 的资料、发帖与评论`
|
||||
: `查看 ${data.user.nickname} 的资料与发帖`,
|
||||
title,
|
||||
description,
|
||||
...(await requestCanonical(`/u/${data.user.id}`, query)),
|
||||
};
|
||||
} catch {
|
||||
return { title: "用户不存在" };
|
||||
@@ -135,11 +156,26 @@ export default async function UserPage({ params, searchParams }: UserPageProps)
|
||||
const visibleNav = navItems.filter((t) => !t.ownerOnly || isOwner);
|
||||
const tabHref = (t: UserTab) => (t === "posts" ? `/u/${id}` : `/u/${id}?tab=${t}`);
|
||||
|
||||
const profileQuery: Record<string, string | number> = {};
|
||||
if (allowComments && effectiveTab === "comments") profileQuery.tab = "comments";
|
||||
if (page > 1) profileQuery.page = page;
|
||||
const profileLd =
|
||||
effectiveTab === "settings" || effectiveTab === "security"
|
||||
? null
|
||||
: profileJsonLd({
|
||||
id: u.id,
|
||||
name: u.nickname || u.username,
|
||||
username: u.username,
|
||||
signature: (u.signature || "").trim() || undefined,
|
||||
pageUrl: absoluteCanonical(`/u/${u.id}`, profileQuery),
|
||||
});
|
||||
|
||||
/** 本页卡片统一阴影;暗色随 color-mix 自动加深 */
|
||||
const cardShadow = "0 1px 3px color-mix(in srgb, #000 18%, transparent)";
|
||||
|
||||
return (
|
||||
<div>
|
||||
<JsonLd data={profileLd} />
|
||||
<nav className="meta -mt-4 sm:-mt-6 mb-1.5 flex items-center gap-1 text-[12.5px] leading-none">
|
||||
<Link href="/" className="hover:text-[var(--accent)] transition-colors">首页</Link>
|
||||
<ChevronRight size={13} />
|
||||
|
||||
Reference in New Issue
Block a user