Files
jiang13-bbs/frontend/components/PinnedPosts.tsx
freefire 1eaf3903d4 feat: 新增大量社区功能与基础组件,优化站点整体体验
- 新增事件总线式toast通知系统
- 新增头像、阅读进度、404/500错误页等基础组件
- 重构页脚、布局、分页、点赞按钮等现有组件
- 新增用户个人页、通知中心、帖子编辑/发布/置顶/推荐管理功能
- 优化登录注册页面样式与交互
- 修复路径类型文件引用,更新站点元信息与字体配置
2026-09-12 04:30:02 +08:00

92 lines
3.4 KiB
TypeScript

import Link from "next/link";
import { Pin } from "lucide-react";
import type { PostListItem } from "@/lib/api";
import Avatar from "./Avatar";
import { IconComment, IconEye } from "./Icons";
function formatTime(dateStr: string) {
const d = new Date(dateStr);
return `${d.getFullYear()}.${String(d.getMonth() + 1).padStart(2, "0")}.${String(
d.getDate()
).padStart(2, "0")}`;
}
/**
* 管理员置顶区:独立于"今日精选"和普通列表。
* 陶土色语义(与 badge-pin 一致),紧凑排列,一眼识别为公告性质内容。
*/
export default function PinnedPosts({
posts,
showBoard = true,
}: {
posts: PostListItem[];
showBoard?: boolean;
}) {
if (posts.length === 0) return null;
return (
<section className="mb-6" aria-label="置顶讨论">
<div className="flex items-center gap-2 mb-2.5 px-1">
<span
className="w-6 h-6 rounded-full flex items-center justify-center"
style={{ background: "var(--clay-soft)", color: "var(--clay)" }}
>
<Pin size={12} fill="currentColor" strokeWidth={2.4} />
</span>
<h2 className="text-[13.5px] font-extrabold tracking-wide" style={{ color: "var(--clay)" }}>
置顶讨论
</h2>
<span className="meta text-xs">管理员置顶 · {posts.length}</span>
</div>
<div className="panel overflow-hidden">
{posts.map((p, i) => (
<Link
key={p.id}
href={`/post/${p.id}`}
className="group flex items-center gap-3 sm:gap-3.5 px-4 sm:px-5 py-3.5 transition-colors hover:bg-[var(--panel-2)]"
style={i > 0 ? { borderTop: "1px solid var(--line)" } : undefined}
>
<Avatar name={p.user.nickname || p.user.username} size={36} />
<div className="flex-1 min-w-0">
<h3
className="text-[14.5px] font-bold leading-snug truncate transition-colors group-hover:text-[var(--accent)]"
style={{ color: "var(--ink)" }}
>
{p.title}
</h3>
<div className="meta flex items-center gap-2 mt-1 text-xs min-w-0">
<span className="truncate">{p.user.nickname}</span>
<span aria-hidden>·</span>
<span className="shrink-0">{formatTime(p.created_at)}</span>
{showBoard && (
<>
<span aria-hidden>·</span>
<span className="truncate">{p.board.name}</span>
</>
)}
{p.recommended && <span className="badge-rec !text-[10.5px] !px-1.5 !py-0 shrink-0">推荐</span>}
</div>
</div>
<div className="hidden sm:flex items-center gap-3 shrink-0 meta text-[12.5px]">
<span className="inline-flex items-center gap-1.5" aria-label={`${p.comment_count} 条评论`}>
<IconComment size={14} /> {p.comment_count}
</span>
<span className="inline-flex items-center gap-1.5" aria-label={`${p.view_count} 次浏览`}>
<IconEye size={14} /> {p.view_count}
</span>
</div>
<Pin
size={13}
className="shrink-0 hidden sm:block"
style={{ color: "var(--clay)" }}
fill="currentColor"
strokeWidth={2.2}
/>
</Link>
))}
</div>
</section>
);
}