feat: 可配置站点 URL 风格

- 新增 urlStyle 工具与测试:postPath/userPath/sitePagePath 统一生成链接
- 管理端新增 UrlStylePanel 设置面板,settings 服务与 handler 适配
- 全站路由链接与 JSON-LD/sitemap 切换为统一 URL 生成
- middleware 与相关组件适配
This commit is contained in:
2026-09-27 04:01:42 +08:00
parent 1d862a0dd3
commit 7a44c1f2cf
64 changed files with 1183 additions and 200 deletions

View File

@@ -17,6 +17,7 @@ import {
SiteDocMasthead,
} from "@/components/site-doc";
import { requestCanonical } from "@/lib/canonicalMeta";
import { pagePath } from "@/lib/urlStyle";
import { webPageJsonLd } from "@/lib/jsonLd";
import JsonLd from "@/components/JsonLd";
@@ -29,6 +30,7 @@ export async function generateMetadata({ params }: PageProps): Promise<Metadata>
const data = await fetchSitePageBySlug(slug).catch(() => null);
if (!data) return { title: "页面不存在" };
const p = data.page;
const urlStyle = (await getPublicSettingsCached()).url_style;
return {
title: p.title,
description: p.excerpt || p.title,
@@ -38,7 +40,7 @@ export async function generateMetadata({ params }: PageProps): Promise<Metadata>
type: "article",
publishedTime: p.created_at,
},
...(await requestCanonical(`/p/${p.slug}`)),
...(await requestCanonical(pagePath(urlStyle, p.slug))),
};
}
@@ -58,6 +60,7 @@ export default async function SitePagePublic({ params }: PageProps) {
const announcements = overview?.announcements ?? [];
const canManagePages = !!me.user && isAdminOrAbove(me.user.role);
const siteLead = settings.site_description?.trim() || undefined;
const urlStyle = settings.url_style;
const toc = extractToc(p.content);
const headingToc = markdownHeadingToc(toc);
const readingMinutes = estimateReadingMinutes(p.content, p.title.length);
@@ -76,7 +79,7 @@ export default async function SitePagePublic({ params }: PageProps) {
const jsonLd = webPageJsonLd({
name: p.title,
description: p.excerpt || undefined,
path: `/p/${p.slug}`,
path: pagePath(urlStyle, p.slug),
datePublished: p.created_at,
dateModified: p.updated_at,
});