import { memo } from 'react'; import { Eye, Image as ImageIcon, MessageCircle, ThumbsUp } from 'lucide-react'; import BoardBadge from '@/components/BoardBadge'; import FeaturedIcon from '@/components/FeaturedIcon'; import PinnedIcon from '@/components/PinnedIcon'; import UserLink from '@/components/UserLink'; import type { PostItem } from '../api/types'; import type { FeedSort } from './FeedSortBar'; import { formatTime } from '../utils/content'; import { postPath } from '../utils/permalink'; import { excerptFromHTML, firstImageFromHTML } from '../utils/seoText'; interface Props { post: PostItem; sort?: FeedSort; onSelect: (id: number) => void; } function PostListItem({ post, sort = 'latest', onSelect }: Props) { const initial = post.user?.nickname?.[0] || '?'; const timeLabel = sort === 'reply' ? (post.last_reply_at ? `${formatTime(post.last_reply_at)} 回复` : '暂无回复') : formatTime(post.created_at); const commentCount = post.comment_count ?? 0; const likeCount = post.like_count ?? 0; const viewCount = post.view_count ?? 0; const href = postPath(post.id); const excerpt = excerptFromHTML(post.content || '', 72); const hasImage = !!firstImageFromHTML(post.content || ''); const openPost = () => onSelect(post.id); const onKeyDown = (e: React.KeyboardEvent) => { if (e.key === 'Enter' || e.key === ' ') { e.preventDefault(); openPost(); } }; const onTitleClick = (e: React.MouseEvent) => { // 修饰键 / 非左键:交给浏览器(新标签等) if (e.defaultPrevented || e.button !== 0 || e.metaKey || e.ctrlKey || e.shiftKey || e.altKey) { e.stopPropagation(); return; } e.preventDefault(); e.stopPropagation(); openPost(); }; return (
{post.user?.avatar ? : initial}
· {timeLabel}
{(post.featured || post.pinned || post.status === 'pending' || post.status === 'rejected') && (
{post.status === 'pending' && ( 审核中 )} {post.status === 'rejected' && ( 未通过 )} {post.featured && ( 精华 )} {post.pinned && ( 置顶 )}
)}
{post.title} {excerpt &&

{excerpt}

}
{post.board && }
{hasImage && ( )} {commentCount} {likeCount} {viewCount}
); } export default memo(PostListItem);