- 新增附件模型与上传服务,拆分头像上传/管理逻辑 - 重构用户资料接口,移除直接修改头像字段,改用专用上传接口 - 添加站点公开设置API与管理员外观配置页 - 全局替换hover背景为accent-soft,优化交互一致性 - 完善头像组件,支持图片加载失败回退与src更新重置 - 新增用户状态事件总线,解决同页头像更新不及时问题 - 调整依赖包顺序与CI依赖版本 - 重构板块列表接口,新增帖子计数 - 迁移账号设置到用户主页tab,合并重复代码
109 lines
4.4 KiB
TypeScript
109 lines
4.4 KiB
TypeScript
import Link from "next/link";
|
||
import type { Metadata } from "next";
|
||
import { ChevronRight, MessagesSquare, LayoutGrid } from "lucide-react";
|
||
import { fetchBoards } from "@/lib/api";
|
||
|
||
export const metadata: Metadata = {
|
||
title: "板块目录 · 姜十三论坛",
|
||
description: "浏览论坛全部板块,找到感兴趣的话题社区",
|
||
};
|
||
|
||
// 板块汇总列表页:首页左栏「板块目录」标题的落地页,
|
||
// 展示全部板块(介绍 + 讨论量),点击进入板块独立页
|
||
export default async function BoardsPage() {
|
||
const { boards } = await fetchBoards();
|
||
const totalPosts = boards.reduce((sum, b) => sum + (b.post_count || 0), 0);
|
||
|
||
return (
|
||
<div>
|
||
{/* 面包屑 */}
|
||
<nav className="meta mb-5 flex items-center gap-1.5 text-[13px]">
|
||
<Link href="/" className="hover:text-[var(--accent)] transition-colors">首页</Link>
|
||
<ChevronRight size={13} />
|
||
<span style={{ color: "var(--accent)" }}>板块目录</span>
|
||
</nav>
|
||
|
||
{/* 页头 */}
|
||
<div className="panel p-6 sm:p-7 mb-6 relative overflow-hidden">
|
||
<span
|
||
aria-hidden
|
||
className="absolute -top-16 -right-12 w-48 h-48 rounded-full"
|
||
style={{ background: "var(--accent-soft)" }}
|
||
/>
|
||
<div className="relative flex items-center gap-4">
|
||
<span
|
||
className="w-14 h-14 sm:w-16 sm:h-16 rounded-2xl flex items-center justify-center shrink-0"
|
||
style={{ background: "var(--accent-soft)", color: "var(--accent)" }}
|
||
>
|
||
<LayoutGrid size={28} />
|
||
</span>
|
||
<div>
|
||
<h1 className="text-2xl sm:text-[28px] font-extrabold tracking-tight" style={{ color: "var(--ink)" }}>
|
||
板块目录
|
||
</h1>
|
||
<p className="meta mt-1.5">
|
||
共 {boards.length} 个板块 · {totalPosts} 篇讨论
|
||
</p>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
{/* 板块卡片网格 */}
|
||
{boards.length === 0 ? (
|
||
<div className="panel text-center py-20 px-6">
|
||
<span
|
||
className="inline-flex w-14 h-14 rounded-full items-center justify-center mb-4"
|
||
style={{ background: "var(--accent-soft)", color: "var(--accent)" }}
|
||
>
|
||
<MessagesSquare size={26} />
|
||
</span>
|
||
<p className="font-bold text-lg" style={{ color: "var(--ink)" }}>还没有任何板块</p>
|
||
<p className="meta mt-1.5">板块由管理员创建,敬请期待</p>
|
||
</div>
|
||
) : (
|
||
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-4">
|
||
{boards.map((b, i) => (
|
||
<Link
|
||
key={b.id}
|
||
href={`/board/${b.id}`}
|
||
className="j13-module group flex items-start gap-3.5 transition-[border-color,background] duration-150 hover:border-[var(--nav-active-line)] hover:bg-[var(--accent-soft)] focus-visible:bg-[var(--accent-soft)]"
|
||
aria-label={`${b.name}板块,${b.post_count} 篇讨论`}
|
||
>
|
||
<span className={`av-${i % 8} j13-bcard-ico !w-11 !h-11 !text-lg`} aria-hidden="true">
|
||
{b.name.slice(0, 1)}
|
||
</span>
|
||
<span className="min-w-0 flex-1">
|
||
<span className="flex items-center justify-between gap-2">
|
||
<span className="truncate text-[15px] font-extrabold" style={{ color: "var(--ink)" }}>
|
||
{b.name}
|
||
</span>
|
||
<span className="meta shrink-0 text-[11.5px] tabular-nums">{b.post_count} 篇</span>
|
||
</span>
|
||
{b.description?.trim() && (
|
||
<span
|
||
className="block mt-1 text-[12.5px] leading-relaxed line-clamp-2"
|
||
style={{ color: "var(--ink-3)" }}
|
||
>
|
||
{b.description.trim()}
|
||
</span>
|
||
)}
|
||
<span
|
||
className="mt-2.5 inline-flex items-center gap-0.5 text-[12px] font-bold transition-colors group-hover:text-[var(--accent)]"
|
||
style={{ color: "var(--ink-2)" }}
|
||
>
|
||
进入板块
|
||
<ChevronRight
|
||
size={12}
|
||
className="transition-transform group-hover:translate-x-0.5"
|
||
aria-hidden="true"
|
||
/>
|
||
</span>
|
||
</span>
|
||
</Link>
|
||
))}
|
||
</div>
|
||
)}
|
||
</div>
|
||
);
|
||
}
|