FeedCard.tsx 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687
  1. import Link from 'next/link';
  2. import { BadgeCheck } from 'lucide-react';
  3. import { FeedCard as FeedCardType } from '@/types/feed/card';
  4. import { formatDate } from '@/lib/utils/client';
  5. import FeedActionBar from './FeedActionBar';
  6. import TagChip from './TagChip';
  7. type Props = {
  8. card: FeedCardType;
  9. onTagClick?: (slug: string) => void;
  10. };
  11. export default function FeedCard({ card }: Props) {
  12. const displayName = card.authorName || card.authorSID || '알 수 없음';
  13. const avatarInitial = (displayName.charAt(0) || '?').toUpperCase();
  14. return (
  15. <article className="feed__card" data-post-id={card.postID}>
  16. <header className="feed__card-header">
  17. {card.authorSID ? (
  18. <Link href={`/user/${card.authorSID}`} className="feed__card-avatar" aria-label={`${displayName} 프로필`}>
  19. {card.authorThumb ? (
  20. <img src={card.authorThumb} alt={displayName} />
  21. ) : (
  22. <span className="feed__card-avatar-fallback">{avatarInitial}</span>
  23. )}
  24. </Link>
  25. ) : (
  26. <span className="feed__card-avatar">
  27. <span className="feed__card-avatar-fallback">{avatarInitial}</span>
  28. </span>
  29. )}
  30. <div className="feed__card-meta">
  31. <div className="feed__card-author-row">
  32. {card.authorSID ? (
  33. <Link href={`/user/${card.authorSID}`} className="feed__card-author">{displayName}</Link>
  34. ) : (
  35. <span className="feed__card-author">{displayName}</span>
  36. )}
  37. {card.isCreator && (
  38. <span className="feed__card-badge" title="크리에이터">
  39. <BadgeCheck size={14} fill="currentColor" stroke="#fff" strokeWidth={2.5} />
  40. </span>
  41. )}
  42. <span className="feed__card-time">· {formatDate(card.createdAt)}</span>
  43. </div>
  44. {card.authorSummary && (
  45. <p className="feed__card-summary" title="오늘의 한마디">{card.authorSummary ? '“' + card.authorSummary + '”' : '-'}</p>
  46. )}
  47. </div>
  48. </header>
  49. {card.contentExcerpt && (
  50. <Link href={`/feed/post/${card.postID}`} className="feed__card-body">
  51. <p>{card.contentExcerpt}</p>
  52. </Link>
  53. )}
  54. {card.thumbnail && (
  55. <Link href={`/feed/post/${card.postID}`} className="feed__card-thumbnail">
  56. <img src={card.thumbnail} alt={card.subject} loading="lazy" />
  57. {card.images > 1 && (
  58. <span className="feed__card-image-count">+{card.images - 1}</span>
  59. )}
  60. </Link>
  61. )}
  62. {card.tags.length > 0 && (
  63. <div className="feed__card-tags">
  64. {card.tags.slice(0, 5).map((tag) => (
  65. <TagChip key={tag.slug} name={tag.name} slug={tag.slug} />
  66. ))}
  67. </div>
  68. )}
  69. <FeedActionBar
  70. postID={card.postID}
  71. initialLikes={card.likes}
  72. initialComments={card.comments}
  73. initialBookmarks={card.bookmarks}
  74. />
  75. </article>
  76. );
  77. }