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

@@ -13,6 +13,7 @@ import {
import { formatDateTime, formatRelative } from "@/lib/format";
import { toast } from "@/lib/toast";
import ConfirmDialog from "@/components/ConfirmDialog";
import { useUrlStyle } from "@/components/SiteBrandProvider";
import {
AdminEmpty,
AdminPageHeader,
@@ -62,6 +63,7 @@ export default function AnnouncementAdmin({
}) {
const router = useRouter();
const searchParams = useSearchParams();
const urlStyle = useUrlStyle();
const statusFilter = readStatus(searchParams.get("status"));
const [list, setList] = useState(initial);
const [loadError, setLoadError] = useState(initError);
@@ -215,7 +217,7 @@ export default function AnnouncementAdmin({
<span className={`j13-anno-tag is-${a.tag_color}`} title={a.tag}>
{a.tag}
</span>
{a.published ? <code>{announcementPublicPath(a.id)}</code> : null}
{a.published ? <code>{announcementPublicPath(a.id, urlStyle)}</code> : null}
</p>
{summary ? <p className="admin-doc-excerpt" title={summary}>{summary}</p> : null}
</td>
@@ -241,7 +243,7 @@ export default function AnnouncementAdmin({
</Link>
{a.published ? (
<a
href={announcementPublicPath(a.id)}
href={announcementPublicPath(a.id, urlStyle)}
target="_blank"
rel="noopener noreferrer"
className="admin-doc-textbtn"

View File

@@ -15,6 +15,7 @@ import { toast } from "@/lib/toast";
import MarkdownEditor from "@/components/MarkdownEditor";
import { AdminField, AdminSegmented, AdminStatusChip, AdminSwitch } from "@/components/admin";
import ConfirmDialog from "@/components/ConfirmDialog";
import { useUrlStyle } from "@/components/SiteBrandProvider";
import useUnsavedGuard from "@/hooks/useUnsavedGuard";
import { ANNOUNCEMENT_COLORS, announcementPublicPath } from "./announcementColors";
@@ -117,6 +118,7 @@ export default function AnnouncementComposeClient({
}) {
const router = useRouter();
const searchParams = useSearchParams();
const urlStyle = useUrlStyle();
const status = readStatus(searchParams.get("status"));
const backHref = listHref(status);
const loaded = useMemo(() => toForm(initial), [initial]);
@@ -146,7 +148,7 @@ export default function AnnouncementComposeClient({
};
const canViewOnline = saved?.published === true && saved.id > 0;
const publicPath = saved ? announcementPublicPath(saved.id) : "";
const publicPath = saved ? announcementPublicPath(saved.id, urlStyle) : "";
async function commit() {
if (saving) return;
@@ -227,7 +229,7 @@ export default function AnnouncementComposeClient({
async function copyAddress() {
if (!saved) return;
const url = `${(origin || window.location.origin).replace(/\/$/, "")}${announcementPublicPath(saved.id)}`;
const url = `${(origin || window.location.origin).replace(/\/$/, "")}${announcementPublicPath(saved.id, urlStyle)}`;
try {
await navigator.clipboard.writeText(url);
toast("已复制访问地址", "ok");

View File

@@ -1,4 +1,5 @@
import type { AnnouncementColor } from "@/lib/api";
import { announcementPath, type UrlStyle } from "@/lib/urlStyle";
/** 标签色板:与后端 AnnouncementColor 白名单一致(12 色) */
export const ANNOUNCEMENT_COLORS: { value: AnnouncementColor; label: string }[] = [
@@ -17,6 +18,6 @@ export const ANNOUNCEMENT_COLORS: { value: AnnouncementColor; label: string }[]
];
/** 公告公开路径。前台是 /announcement/[id],列表和线上查看用同一条。 */
export function announcementPublicPath(id: number): string {
return `/announcement/${id}`;
export function announcementPublicPath(id: number, urlStyle: UrlStyle = "default"): string {
return announcementPath(urlStyle, id);
}