feat: 可配置站点 URL 风格
- 新增 urlStyle 工具与测试:postPath/userPath/sitePagePath 统一生成链接 - 管理端新增 UrlStylePanel 设置面板,settings 服务与 handler 适配 - 全站路由链接与 JSON-LD/sitemap 切换为统一 URL 生成 - middleware 与相关组件适配
This commit is contained in:
@@ -36,6 +36,8 @@ import {
|
||||
import { isOwner, ROLES } from "@/lib/roles";
|
||||
import { formatDate, formatRelative } from "@/lib/format";
|
||||
import { realtime } from "@/lib/realtime";
|
||||
import { userPath } from "@/lib/urlStyle";
|
||||
import { useUrlStyle } from "@/components/SiteBrandProvider";
|
||||
import Avatar from "@/components/Avatar";
|
||||
import RoleBadge from "@/components/RoleBadge";
|
||||
import Modal from "@/components/Modal";
|
||||
@@ -302,6 +304,7 @@ export default function UsersAdmin({
|
||||
currentUserId: number;
|
||||
currentUserRole: string;
|
||||
}) {
|
||||
const urlStyle = useUrlStyle();
|
||||
const [users, setUsers] = useState<AdminUser[]>(initial?.users ?? []);
|
||||
const [summary, setSummary] = useState<AdminUserSummary>(
|
||||
initial?.summary ?? {
|
||||
@@ -686,7 +689,7 @@ export default function UsersAdmin({
|
||||
return (
|
||||
<div className="flex items-center gap-1.5 flex-wrap">
|
||||
{auditBtn}
|
||||
<Link href={`/u/${u.id}`} className="btn btn-line btn-sm gap-1" aria-label={`查看 ${u.nickname} 的个人主页`}>
|
||||
<Link href={userPath(urlStyle, u.id)} className="btn btn-line btn-sm gap-1" aria-label={`查看 ${u.nickname} 的个人主页`}>
|
||||
<ExternalLink size={13} />
|
||||
主页
|
||||
</Link>
|
||||
@@ -697,7 +700,7 @@ export default function UsersAdmin({
|
||||
return (
|
||||
<div className="flex items-center gap-1.5 flex-wrap">
|
||||
{auditBtn}
|
||||
<Link href={`/u/${u.id}`} className="btn btn-line btn-sm gap-1" aria-label={`查看 ${u.nickname} 的个人主页`}>
|
||||
<Link href={userPath(urlStyle, u.id)} className="btn btn-line btn-sm gap-1" aria-label={`查看 ${u.nickname} 的个人主页`}>
|
||||
<ExternalLink size={13} />
|
||||
主页
|
||||
</Link>
|
||||
@@ -718,7 +721,7 @@ export default function UsersAdmin({
|
||||
return (
|
||||
<div className="flex items-center gap-1.5 flex-wrap">
|
||||
{auditBtn}
|
||||
<Link href={`/u/${u.id}`} className="btn btn-line btn-sm gap-1" aria-label={`查看 ${u.nickname} 的个人主页`}>
|
||||
<Link href={userPath(urlStyle, u.id)} className="btn btn-line btn-sm gap-1" aria-label={`查看 ${u.nickname} 的个人主页`}>
|
||||
<ExternalLink size={13} />
|
||||
主页
|
||||
</Link>
|
||||
|
||||
@@ -14,7 +14,9 @@ import {
|
||||
} from "@/lib/api";
|
||||
import { formatDate, formatRelative } from "@/lib/format";
|
||||
import Avatar from "@/components/Avatar";
|
||||
import { useUrlStyle } from "@/components/SiteBrandProvider";
|
||||
import RoleBadge from "@/components/RoleBadge";
|
||||
import { postPath, userPath } from "@/lib/urlStyle";
|
||||
import {
|
||||
AdminEmpty,
|
||||
AdminPager,
|
||||
@@ -72,6 +74,7 @@ export default function UserAuditClient({
|
||||
initialPostsTotal: number;
|
||||
initError: string;
|
||||
}) {
|
||||
const urlStyle = useUrlStyle();
|
||||
const [profile] = useState(initial);
|
||||
const [tab, setTab] = useState<TabKey>("posts");
|
||||
const [loading, setLoading] = useState(false);
|
||||
@@ -231,7 +234,7 @@ export default function UserAuditClient({
|
||||
</p>
|
||||
</div>
|
||||
<Link
|
||||
href={`/u/${u.id}`}
|
||||
href={userPath(urlStyle, u.id)}
|
||||
className="btn btn-line btn-sm gap-1.5 shrink-0"
|
||||
target="_blank"
|
||||
>
|
||||
@@ -318,7 +321,7 @@ export default function UserAuditClient({
|
||||
</p>
|
||||
) : (
|
||||
<Link
|
||||
href={`/post/${p.id}`}
|
||||
href={postPath(urlStyle, p.id)}
|
||||
className="text-[14px] font-medium hover:underline"
|
||||
style={{ color: "var(--ink)" }}
|
||||
>
|
||||
@@ -353,7 +356,7 @@ export default function UserAuditClient({
|
||||
<span className="text-[11.5px] meta">帖子 #{c.post_id}</span>
|
||||
) : (
|
||||
<Link
|
||||
href={`/post/${c.post_id}#comment-${c.id}`}
|
||||
href={`${postPath(urlStyle, c.post_id)}#comment-${c.id}`}
|
||||
className="text-[11.5px] hover:underline"
|
||||
style={{ color: "var(--accent)" }}
|
||||
>
|
||||
|
||||
Reference in New Issue
Block a user