feat: 可配置站点 URL 风格
- 新增 urlStyle 工具与测试:postPath/userPath/sitePagePath 统一生成链接 - 管理端新增 UrlStylePanel 设置面板,settings 服务与 handler 适配 - 全站路由链接与 JSON-LD/sitemap 切换为统一 URL 生成 - middleware 与相关组件适配
This commit is contained in:
@@ -29,6 +29,8 @@ import type {
|
||||
} from "@/lib/api";
|
||||
import Avatar from "@/components/Avatar";
|
||||
import { AdText } from "@/components/AdText";
|
||||
import { getPublicSettingsCached } from "@/lib/serverData";
|
||||
import { announcementPath, postPath, userPath, pagePath } from "@/lib/urlStyle";
|
||||
import { PulseCheckin } from "./CheckinCard";
|
||||
import { FRIEND_LINKS } from "@/lib/friendLinks";
|
||||
import { formatCompact, formatShortDate } from "@/lib/format";
|
||||
@@ -136,7 +138,7 @@ export function PulseCard({
|
||||
|
||||
/* ---------- 关于本站(侧栏页目录,置于右栏最底) ---------- */
|
||||
|
||||
export function AboutSite({
|
||||
export async function AboutSite({
|
||||
pages,
|
||||
siteDescription,
|
||||
canManagePages,
|
||||
@@ -147,6 +149,7 @@ export function AboutSite({
|
||||
}) {
|
||||
if (pages.length === 0 && !canManagePages) return null;
|
||||
const lead = siteDescription?.trim() ?? "";
|
||||
const urlStyle = (await getPublicSettingsCached()).url_style;
|
||||
|
||||
return (
|
||||
<section className="j13-module j13-about" aria-label="关于本站">
|
||||
@@ -160,7 +163,7 @@ export function AboutSite({
|
||||
const Icon = pageGlyph(p.slug);
|
||||
return (
|
||||
<li key={p.id}>
|
||||
<Link href={`/p/${p.slug}`} className="j13-about-item">
|
||||
<Link href={pagePath(urlStyle, p.slug)} className="j13-about-item">
|
||||
<span className="j13-about-ico" aria-hidden="true">
|
||||
<Icon size={15} strokeWidth={2} />
|
||||
</span>
|
||||
@@ -181,13 +184,14 @@ export function AboutSite({
|
||||
|
||||
/* ---------- 站点公告 ---------- */
|
||||
|
||||
export function Announcements({
|
||||
export async function Announcements({
|
||||
items,
|
||||
canManageAnnouncements,
|
||||
}: {
|
||||
items: AnnouncementSummary[];
|
||||
canManageAnnouncements?: boolean;
|
||||
}) {
|
||||
const urlStyle = (await getPublicSettingsCached()).url_style;
|
||||
return (
|
||||
<section className="j13-module" aria-label="站点公告">
|
||||
<div className="flex items-center justify-between gap-2">
|
||||
@@ -218,7 +222,7 @@ export function Announcements({
|
||||
{items.map((a) => (
|
||||
<li key={a.id}>
|
||||
<Link
|
||||
href={`/announcement/${a.id}`}
|
||||
href={announcementPath(urlStyle, a.id)}
|
||||
className="j13-anno-item"
|
||||
data-tip={a.title}
|
||||
>
|
||||
@@ -254,7 +258,8 @@ export function Announcements({
|
||||
|
||||
/* ---------- 热门榜 ---------- */
|
||||
|
||||
export function HotRanking({ posts, allowComments }: { posts: PostListItem[]; allowComments: boolean }) {
|
||||
export async function HotRanking({ posts, allowComments }: { posts: PostListItem[]; allowComments: boolean }) {
|
||||
const urlStyle = (await getPublicSettingsCached()).url_style;
|
||||
return (
|
||||
<section className="j13-module" aria-label="热门讨论">
|
||||
<p className="j13-module-title mb-1.5">
|
||||
@@ -266,7 +271,7 @@ export function HotRanking({ posts, allowComments }: { posts: PostListItem[]; al
|
||||
<ol className="j13-ranklist">
|
||||
{posts.map((p, i) => (
|
||||
<li key={p.id}>
|
||||
<Link href={`/post/${p.id}`} className="j13-rank" data-tip={p.title}>
|
||||
<Link href={postPath(urlStyle, p.id)} className="j13-rank" data-tip={p.title}>
|
||||
<span className="j13-rank-no">{i + 1}</span>
|
||||
<span className="min-w-0 flex-1">
|
||||
<span className="j13-rank-title truncate">
|
||||
@@ -294,8 +299,9 @@ export function HotRanking({ posts, allowComments }: { posts: PostListItem[]; al
|
||||
|
||||
/* ---------- 最新注册 ---------- */
|
||||
|
||||
export function NewUsers({ users }: { users: NewUser[] }) {
|
||||
export async function NewUsers({ users }: { users: NewUser[] }) {
|
||||
if (users.length === 0) return null;
|
||||
const urlStyle = (await getPublicSettingsCached()).url_style;
|
||||
return (
|
||||
<section className="j13-module" aria-label="最新注册">
|
||||
<p className="j13-module-title mb-3">
|
||||
@@ -307,7 +313,7 @@ export function NewUsers({ users }: { users: NewUser[] }) {
|
||||
return (
|
||||
<li key={u.id}>
|
||||
<Link
|
||||
href={`/u/${u.id}`}
|
||||
href={userPath(urlStyle, u.id)}
|
||||
className="flex flex-col items-center gap-1.5 rounded-lg px-1 py-1 transition-colors hover:bg-[var(--item-hover-bg)] focus-visible:bg-[var(--item-hover-bg)]"
|
||||
>
|
||||
<Avatar name={name} src={u.avatar} size={38} />
|
||||
@@ -329,7 +335,8 @@ export function NewUsers({ users }: { users: NewUser[] }) {
|
||||
|
||||
/* ---------- 活跃成员(本周发帖 / 回复) ---------- */
|
||||
|
||||
export function ActiveUsers({ users, allowComments }: { users: ActiveUser[]; allowComments: boolean }) {
|
||||
export async function ActiveUsers({ users, allowComments }: { users: ActiveUser[]; allowComments: boolean }) {
|
||||
const urlStyle = (await getPublicSettingsCached()).url_style;
|
||||
return (
|
||||
<section className="j13-module" aria-label="本周活跃成员">
|
||||
<p className="j13-module-title mb-2">
|
||||
@@ -346,7 +353,7 @@ export function ActiveUsers({ users, allowComments }: { users: ActiveUser[]; all
|
||||
const name = u.nickname || u.username;
|
||||
return (
|
||||
<li key={u.id}>
|
||||
<Link href={`/u/${u.id}`} className="j13-raillink" data-tip={name}>
|
||||
<Link href={userPath(urlStyle, u.id)} className="j13-raillink" data-tip={name}>
|
||||
<Avatar name={name} src={u.avatar} size={30} />
|
||||
<span className="flex-1 min-w-0">
|
||||
<span
|
||||
|
||||
Reference in New Issue
Block a user