公开页补齐自引用 Canonical 与按类型的结构化数据,图片补上说明文字。
后台设置和内容编辑改成可导航布局;部署用访客 origin 生成 Canonical,避免落到容器地址。 Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -10,11 +10,12 @@ export type FeedSort = "latest" | "new" | "recommended";
|
||||
|
||||
const TAB_KEYS: FeedSort[] = ["latest", "new", "recommended"];
|
||||
|
||||
// 在指定板块内切换排序时保留 ?board=
|
||||
function tabHref(key: FeedSort, boardId: number) {
|
||||
// 在指定板块内切换排序时保留 ?board=;默认排序不写入 URL
|
||||
function tabHref(key: FeedSort, boardId: number, allowComments: boolean) {
|
||||
const params = new URLSearchParams();
|
||||
if (boardId > 0) params.set("board", String(boardId));
|
||||
if (key !== "latest") params.set("sort", key);
|
||||
const def = allowComments ? "latest" : "new";
|
||||
if (key !== def) params.set("sort", key);
|
||||
const qs = params.toString();
|
||||
return qs ? `/?${qs}` : "/";
|
||||
}
|
||||
@@ -31,7 +32,7 @@ export default function FeedTabs({ current, boardId = 0 }: { current: FeedSort;
|
||||
e.preventDefault();
|
||||
const next = (i + (e.key === "ArrowRight" ? 1 : keys.length - 1)) % keys.length;
|
||||
tabRefs.current[next]?.focus();
|
||||
router.push(tabHref(keys[next], boardId));
|
||||
router.push(tabHref(keys[next], boardId, allowComments));
|
||||
};
|
||||
|
||||
return (
|
||||
@@ -44,7 +45,7 @@ export default function FeedTabs({ current, boardId = 0 }: { current: FeedSort;
|
||||
ref={(el) => {
|
||||
tabRefs.current[i] = el;
|
||||
}}
|
||||
href={tabHref(key, boardId)}
|
||||
href={tabHref(key, boardId, allowComments)}
|
||||
role="tab"
|
||||
className="j13-tab inline-flex items-center gap-1"
|
||||
aria-selected={current === key}
|
||||
|
||||
@@ -2,8 +2,9 @@
|
||||
|
||||
import Link from "next/link";
|
||||
import { useSearchParams } from "next/navigation";
|
||||
import { PenSquare, Home, LayoutGrid } from "lucide-react";
|
||||
import { PenSquare, Home, LayoutGrid, ShieldCheck } from "lucide-react";
|
||||
import type { BoardWithCount, User } from "@/lib/api";
|
||||
import { isStaff } from "@/lib/roles";
|
||||
|
||||
// 首页壳内板块切换:仅替换中栏帖子流,不离开工作台
|
||||
function boardHref(id: number) {
|
||||
@@ -11,9 +12,10 @@ function boardHref(id: number) {
|
||||
}
|
||||
|
||||
// 桌面左栏:整块模块,与右栏 j13-module 对齐
|
||||
export function WorkspaceNav({ boards }: { boards: BoardWithCount[]; user?: User | null }) {
|
||||
export function WorkspaceNav({ boards, user }: { boards: BoardWithCount[]; user?: User | null }) {
|
||||
const params = useSearchParams();
|
||||
const activeBoard = Number(params.get("board")) || 0;
|
||||
const showAdmin = !!user && isStaff(user.role);
|
||||
|
||||
return (
|
||||
// sticky 必须挂在 flex 子项上:父级 items-start 会把内层缩成内容高,失去粘滞行程
|
||||
@@ -68,6 +70,21 @@ export function WorkspaceNav({ boards }: { boards: BoardWithCount[]; user?: User
|
||||
</Link>
|
||||
))}
|
||||
</div>
|
||||
|
||||
{showAdmin ? (
|
||||
<div className="shrink-0 mt-1.5 pt-1.5" style={{ borderTop: "1px solid var(--line)" }}>
|
||||
<Link href="/admin" className="j13-bcard">
|
||||
<span
|
||||
className="j13-bcard-ico"
|
||||
style={{ background: "var(--accent-soft)", color: "var(--accent)" }}
|
||||
aria-hidden="true"
|
||||
>
|
||||
<ShieldCheck size={15} />
|
||||
</span>
|
||||
<span className="j13-bcard-name flex-1 truncate">管理面板</span>
|
||||
</Link>
|
||||
</div>
|
||||
) : null}
|
||||
</section>
|
||||
</nav>
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user