import { Flame, ListTree, MessageCircle, Tags, Sparkles } from 'lucide-react'; import { useLocation, useSearchParams } from 'react-router-dom'; import { Skeleton } from '@/components/ui/skeleton'; import type { PostItem, RecentComment, TagCount, User } from '../api/types'; import type { PostHeading } from '../utils/postHeadings'; import { useSiteBranding } from '../hooks/useSiteBranding'; import { formatShortDateTime } from '../utils/content'; import TagCloud from './TagCloud'; import UserLink from './UserLink'; import ArticleOutline from './ArticleOutline'; import PostAuthorCard from './PostAuthorCard'; export type PostDetailAside = { author?: User | null; publishedAt?: string; viewCount?: number; headings: PostHeading[]; scrollRoot?: HTMLElement | null; outlineTitle?: string; }; interface Props { hot: PostItem[]; recentComments: RecentComment[]; tags?: TagCount[]; tagsLoading?: boolean; onPostClick: (id: number, opts?: { floor?: number }) => void; /** 首次拉取中,显示骨架避免空态闪烁 */ loading?: boolean; /** 帖子详情:右侧顶部展示作者与目录 */ postDetail?: PostDetailAside | null; } function hotRankClass(index: number): string { if (index === 0) return 'widget-rank widget-rank--1'; if (index === 1) return 'widget-rank widget-rank--2'; if (index === 2) return 'widget-rank widget-rank--3'; return 'widget-rank'; } function HotSkeleton() { return (
{Array.from({ length: 6 }, (_, i) => (
))}
); } function CommentSkeleton() { return (
{Array.from({ length: 5 }, (_, i) => (
))}
); } export default function RightPanel({ hot, recentComments, tags = [], tagsLoading = false, onPostClick, loading = false, postDetail = null, }: Props) { const { branding } = useSiteBranding(); const loc = useLocation(); const [params] = useSearchParams(); const activeTag = params.get('tag') || ''; const hotList = hot?.slice(0, 8) ?? []; const commentList = recentComments?.slice(0, 6) ?? []; // 站点首页:右侧品牌块承担唯一 h1;板块/搜索等页面由 Feed 标题作 h1 const isSiteHome = loc.pathname === '/' && !params.get('board') && !params.get('keyword') && !params.get('tag'); const description = branding.description?.trim() || ''; const slogan = branding.slogan?.trim() || ''; // 有独立简介时展示简介;否则用欢迎语,避免与页脚 slogan 三连重复 const aboutText = description || '欢迎参与讨论,发帖、评论,一起把小圈子聊热。'; // 帖子很少时热门几乎等于主列表,改显示欢迎引导 const showHot = loading || hotList.length >= 4; const showWelcome = !loading && hotList.length > 0 && hotList.length < 4; const isPostDetail = !!postDetail; return (
{isPostDetail && ( <>
{postDetail.outlineTitle || '文章目录'}
)} {!isPostDetail && showWelcome && (
加入讨论

社区还在起步,每条回复都很珍贵。

  • 逛逛板块,找到感兴趣的话题
  • 游客也能评论,登录可点赞收藏
  • 发一篇帖,留下你的痕迹
)} {!isPostDetail && showHot && (
热门帖子
{loading && hotList.length === 0 ? ( ) : hotList.length === 0 ? (
暂无数据
) : hotList.map((item, i) => ( ))}
)} {!isPostDetail && (
标签云
)} {!isPostDetail && (
最新评论
{loading && commentList.length === 0 ? ( ) : commentList.length === 0 ? (
暂无评论
) : commentList.map(item => (
{item.user_id ? ( {item.avatar ? : (item.author?.[0] || '?')} ) : ( {item.avatar ? : (item.author?.[0] || '?')} )}
))}
)} {!isPostDetail && (
{isSiteHome ? (

{branding.name}

) : (

{branding.name}

)}

{aboutText}

{description && slogan && slogan !== description && (

{slogan}

)}
)}
); }