پرتوپرتو

متن پست (PostBody)

محتوای متن + media یک پست — text، image، carousel، video، missing-media

معرفی

PostBody رندرر محتوای یک پست است: متن، تصویر، carousel، ویدیو، یا حالت "media مفقود". building block داخلی PostCard که برای layout های سفارشی نیز export شده. الگوی centering تصویر در packages/ui/CLAUDE.md ("Media centering — canonical pattern") مستند است.

متن خالص

نمونه‌ی متن خالص بدون رسانه مناسب کوتاه‌نوشته‌ها و quote-feedها.

تصویر تکی

پست
نمونه‌ی استفاده مستقیم از سازنده‌های PostCard در یک کارت سفارشی.

زمین بازی

زمین بازی
تجربه‌ام از خرید آنلاین #دیجی‌کالا عالی بود. @sara_pm نظرت چیه؟
تنظیمات
داده
ظاهر
کد این نمونه به‌صورت خودکار قابل تولید نیست — برای کد آماده‌ی copy/paste به بخش «استفاده» در بالای صفحه مراجعه کنید.

چه زمانی مستقیم استفاده کنیم:

  • detail-view پست با sidebar (PostDetailsDrawer از این استفاده می‌کند)
  • لیست fragment-های پست در یک گزارش
  • preview در composer ها

چه زمانی استفاده نکنیم:

  • یک پست در feed → PostCard که خود PostBody را داخل header/actions/metadata قرار می‌دهد

ساختار body

PostBodyData یک discriminated union است:

  • { type: 'text', text } — فقط متن
  • { type: 'image', media, caption? } — یک تصویر
  • { type: 'carousel', media[], caption? } — چند تصویر
  • { type: 'video', media, caption? } — ویدیو با thumbnail
  • { type: 'missing-media', caption?, reason? } — تصویر/ویدیو در دسترس نیست (پلتفرم آن را حذف کرده، fetch fail شد، …)
import { PostBody } from '@parto-system-design/ui'
;<PostBody
  body={{
    type: 'image',
    media: { url: '/post.jpg', alt: 'پست' },
    caption: 'متن زیر تصویر',
  }}
/>

نکته centering

برای letterbox media (image/carousel/video)، الگوی centering canonical به‌صورت:

<div className="relative w-full overflow-hidden flex items-center justify-center">
  {/* blur backdrop */}
  <img src={src} className="absolute inset-0 size-full object-cover object-center blur-2xl opacity-50" aria-hidden />
  {/* foreground */}
  <img src={src} alt={alt} className="relative block max-h-full max-w-full w-auto h-auto object-contain" />
</div>

این از PostBody به‌عنوان implementation reference استفاده می‌شود. هرگز <img class="mx-auto h-full w-auto"> استفاده نکنید — این الگوی شکست‌خورده‌ی شناخته‌شده در DS است.

استفاده

import { PostCard, PostBody } from '@parto-system-design/ui'

// به‌صورت معمول داخل PostCard wired است:
<PostCard post={post} />

// استفاده مستقیم در detail-view یا composer:
<PostBody
  body={post.body}
  context="comfortable"
/>

راهنمای استفاده

بکنید

  • context را با والد همگام نگه دارید (compact در feed، comfortable در detail) — این aspect handling و text-clamping را تنظیم می‌کند - برای تصاویر با aspect ratio غیرعادی، media.aspectRatio را روی PostMediaItem ست کنید تا layout shift نداشته باشید - برای کارت‌های thumbnail-only از thumbnailOnly استفاده کنید — body text را خود والد رندر می‌کند

نکنید

  • الگوی <img class="mx-auto h-full w-auto"> را برای centering استفاده نکنید — این bug-known در DS است (به CLAUDE.md رجوع کنید) - body.type را به‌صورت دلخواه گسترش ندهید — discriminated union در post-card.types.ts تعریف شده و TypeScript exhaustiveness را تأمین می‌کند

جدول ویژگی‌ها

Prop

Type

دسترسی‌پذیری

  • تصاویر alt معنادار از PostMediaItem.alt می‌گیرند؛ اگر alt خالی باشد، تصویر decorative تلقی می‌شود.
  • ویدیوها با آیکون Play overlay رندر می‌شوند؛ Play به‌صورت aria-hidden است و کنترل اصلی از طریق consumer wired می‌شود (PostCard onClick پست را دنبال می‌کند).
  • Carousel از Embla مبتنی است و دکمه‌های Previous/Next ARIA-labeled هستند؛ keyboard navigation با Arrow keys کار می‌کند.
  • لینک‌های داخل متن (URL) با dir="ltr" و target="_blank" + rel="noreferrer" رندر می‌شوند تا screen reader آدرس را به‌درستی بخواند.
  • حالت missing-media با ImageOff icon + caption descriptive رندر می‌شود تا کاربر بفهمد رسانه قابل بازیابی نیست (نه bug سمت کلاینت).

کامپوننت‌های مرتبط

  • کارت کامل پستPostCard
  • detail drawerPostDetailsDrawer
  • بازیابی fail-safe تصویرSafeImage