Files
jiang13-bbs/frontend/components/home/WorkspaceNav.tsx
freefire 24c6dea38c feat: 完成头像上传、站点主题配置与UI优化
- 新增附件模型与上传服务,拆分头像上传/管理逻辑
- 重构用户资料接口,移除直接修改头像字段,改用专用上传接口
- 添加站点公开设置API与管理员外观配置页
- 全局替换hover背景为accent-soft,优化交互一致性
- 完善头像组件,支持图片加载失败回退与src更新重置
- 新增用户状态事件总线,解决同页头像更新不及时问题
- 调整依赖包顺序与CI依赖版本
- 重构板块列表接口,新增帖子计数
- 迁移账号设置到用户主页tab,合并重复代码
2026-09-15 01:06:12 +08:00

128 lines
4.6 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"use client";
import Link from "next/link";
import { useSearchParams } from "next/navigation";
import { PenSquare, Home, ChevronRight } from "lucide-react";
import type { BoardWithCount, User } from "@/lib/api";
// 首页壳内板块切换:仅替换中栏帖子流,不离开工作台
function boardHref(id: number) {
return `/?board=${id}`;
}
// 桌面左栏:发帖 CTA + 板块导航 + 登录态快捷入口
export function WorkspaceNav({ boards, user }: { boards: BoardWithCount[]; user: User | null }) {
const params = useSearchParams();
const activeBoard = Number(params.get("board")) || 0;
const composeHref = user ? "/compose" : "/login?redirect=/compose";
return (
<nav className="hidden lg:block w-56 xl:w-60 shrink-0" aria-label="工作台导航">
<div className="sticky top-24 space-y-5">
<Link href={composeHref} className="btn btn-primary w-full justify-center">
<PenSquare size={16} /> 发起讨论
</Link>
{/* 「全部讨论」是重置筛选的动作入口,与板块目录分区展示;卡片样式与下方板块一致 */}
<div className="space-y-0.5">
<Link href="/" className="j13-bcard" aria-current={activeBoard === 0 ? "page" : undefined}>
<span
className="j13-bcard-ico"
style={{ background: "var(--accent-soft)", color: "var(--accent)" }}
aria-hidden="true"
>
<Home size={16} />
</span>
<span className="j13-bcard-name flex-1 truncate text-[13px] font-bold">
全部讨论
</span>
</Link>
</div>
{/* 板块目录:标题可点击进入板块汇总列表页(/boards);
下方板块卡片点击不离开工作台,仅在中栏筛选该板块帖子流 */}
<div>
<Link
href="/boards"
className="group px-1 mb-2 flex items-center justify-between text-[11.5px] font-bold tracking-[0.08em] uppercase text-[var(--ink-3)] hover:text-[var(--accent)] transition-colors"
aria-label="进入板块目录列表页"
>
<span className="flex items-center">
<span>板块目录</span>
<ChevronRight
size={12}
className="ml-0.5 opacity-0 -translate-x-0.5 group-hover:opacity-100 group-hover:translate-x-0 transition-all"
aria-hidden="true"
/>
</span>
{boards.length > 0 && (
<span className="tracking-normal font-semibold tabular-nums">{boards.length} 个</span>
)}
</Link>
<div className="space-y-2">
{boards.map((b, i) => (
<Link
key={b.id}
href={boardHref(b.id)}
className="j13-bcard"
aria-current={activeBoard === b.id ? "page" : undefined}
aria-label={`${b.name}板块,${b.post_count} 篇讨论`}
>
<span className={`av-${i % 8} j13-bcard-ico`} aria-hidden="true">
{b.name.slice(0, 1)}
</span>
<span className="min-w-0 flex-1 flex items-center justify-between gap-2">
<span className="j13-bcard-name truncate text-[13px] font-bold">
{b.name}
</span>
<span className="meta shrink-0 text-[11px] tabular-nums">{b.post_count} 篇</span>
</span>
</Link>
))}
</div>
</div>
</div>
</nav>
);
}
// 移动端:发帖入口 + 横向滑动板块条
export function WorkspaceNavMobile({
boards,
user,
}: {
boards: BoardWithCount[];
user: User | null;
}) {
const params = useSearchParams();
const activeBoard = Number(params.get("board")) || 0;
const composeHref = user ? "/compose" : "/login?redirect=/compose";
return (
<div className="lg:hidden -mx-4 sm:-mx-6 px-4 sm:px-6">
<div className="j13-chips">
<Link href={composeHref} className="btn btn-primary btn-sm shrink-0">
<PenSquare size={14} /> 发帖
</Link>
<Link
href="/"
className="j13-chip"
aria-current={activeBoard === 0 ? "page" : undefined}
>
<Home size={13} /> 全部
</Link>
{boards.map((b) => (
<Link
key={b.id}
href={boardHref(b.id)}
className="j13-chip"
aria-current={activeBoard === b.id ? "page" : undefined}
>
{b.name}
</Link>
))}
</div>
</div>
);
}