قاب رسانه (MediaFrame)
یک تصویر، ویدئو یا صوت با قاعدهٔ واحد برای هر چیدمان؛ در کارت و جزئیات هرگز بریده نمیشود
معرفی
MediaFrame یک رسانهٔ پست را با قاعدهٔ همان چیدمانی که در آن نشسته نمایش میدهد. قاعدهها تصمیم محصولاند و در خود
جزء ثابت شدهاند، پس هیچ صفحهای لازم نیست دوباره دربارهٔ برش یا نسبت تصویر تصمیم بگیرد:
| چیدمان | قاعده |
|---|---|
card | تمام عرض کارت، با نسبت خود رسانه در بازهٔ 4:5 تا 1.91:1 و حداکثر 500 پیکسل ارتفاع. بیرون از بازه یا بلندتر: کل رسانه روی نسخهٔ محوشدهٔ خودش. هرگز بریده نمیشود. |
tile | تنها چیدمانی که برش دارد: مربع 1:1 یا عمودی 4:5. خود قاب تعاملی نیست؛ موردِ دور کاشی با کلیک جزئیات را باز میکند. |
row | بندانگشتی مربع 96 پیکسلی (72 در حالت فشرده) کنار متن. |
details | بزرگ و کامل: نسبت خود رسانه تا 70٪ ارتفاع صفحه؛ ویدئو با پخشکننده. |
کادر از روی width و height رسانه، پیش از بارگذاری، ساخته میشود؛ پس وقتی تصویر میرسد چیزی جابهجا نمیشود. رسانهٔ بدون
ابعاد کادر مربع میگیرد و کامل در آن نمایش داده میشود؛ ردیف API جستوجوی محتوا ابعاد ندارد (بخش «رسانهٔ بدون ابعاد» را
ببینید).
جزء پایه، نه کارت پست
این جزء یکی از اجزای پایهٔ @partodata/ui/social است که Post، Comment
و Account روی آنها ساخته شدهاند. پست، نظر یا حساب را با همان کامپوننتها نمایش دهید و فهرست
آنها را با EntityCollection؛ کارت یا ردیف را خودتان از اجزای پایه نسازید. جدول انتخاب
در مدل محتوای اجتماعی است.
چه زمانی استفاده کنیم:
- هر جا رسانهٔ یک پست، نظر یا حساب نمایش داده میشود: کارت خبرخوان، ردیف فهرست، کاشی شبکه، نمای جزئیات.
- وقتی رسانه دیر میرسد، منقضی میشود یا ذخیره نشده است؛ این وضعیتها همان کادر را نگه میدارند.
چه زمانی استفاده نکنیم:
- برای تصویر تزئینی، لوگو یا آواتار: از
Avatarاستفاده کنید؛ برای یک تصویر ساده با جایگزین هنگام خطا،layout="fill"همین کامپوننت (از 5.0 جایSafeImage). - برای بریدن تصویر در کارت پایش: این کار عمداً ممکن نیست؛ اینفوگرافیهای پرمتن نباید بریده شوند. اگر برش لازم است، چیدمان
tileاست.



ویدئو، 0:08استفاده
import { MediaFrame, type SocialMedia } from '@partodata/ui/social'
const media: SocialMedia = {
kind: 'image',
src: 'https://cdn.example.com/p/1.jpg',
width: 1080,
height: 1350,
}
export function PostMedia({ index }: { index: number }) {
return <MediaFrame media={media} layout="card" priority={index < 2} />
}priority برای چند مورد اول بالای صفحه است: بارگذاری فوری با اولویت بالا. بقیه تنبل بارگذاری میشوند.
پراکسی و امضای نشانی، یک بار برای کل برنامه
SocialMediaProvider را یک بار در چیدمان کلاینتی برنامه بگذارید. resolveSrc آن هر نشانی رسانه (تصویر، پوستر و ویدئو) را
پیش از بارگذاری به نشانی نهایی تبدیل میکند: پراکسی تصویر، نشانی امضاشده یا تغییر اندازه در CDN. اگر undefined برگرداند،
رسانه «در دسترس نیست» نمایش داده میشود. همهٔ قابهای داخل آن، در فهرست و در جزئیات، از همین قاعده استفاده میکنند؛
resolveSrc روی یک قاب فقط برای همان قاب جای آن را میگیرد.
'use client'
import type { ReactNode } from 'react'
import { SocialMediaProvider } from '@partodata/ui/social'
export function MediaProxy({ children }: { children: ReactNode }) {
return (
<SocialMediaProvider resolveSrc={(url) => `/api/media?u=${encodeURIComponent(url)}`}>
{children}
</SocialMediaProvider>
)
}حالتها و انواع
چیدمانها





ویدئو، 0:08
ویدئو، 0:08




ویدئو، 0:08
ویدئو، 0:08
وضعیتها
pending، failed، expired و unavailable (ذخیره نشده) همان کادر را با یک نشانه و برچسب نگه میدارند؛ نوار صوت در کارت و جزئیات
کادر نسبتدار ندارد و وضعیتش یک ردیف در همان نوار است. نشانیای که هنگام نمایش خطا بدهد هم failed میشود؛ اگر onRetry
داده شده باشد دکمهٔ «تلاش دوباره» نمایش داده میشود (در ردیف، فقط نشانه؛ onRetry و count در row خطای نوعاند). رسانهٔ
حساس در کارت و جزئیات تا وقتی کاربر بخواهد محو میماند و در کاشی و ردیف محو باقی میماند.
ذخیرهشده، ذخیرهنشده، بدون رسانه
سه حالت رسانهٔ یک پست را از هم جدا نشان دهید:
| حالت | داده | نمایش |
|---|---|---|
| رسانه را ذخیره کردهایم | { kind, src, width, height } | خود رسانه |
| در منبع رسانه دارد، ما ذخیره نکردهایم | { kind, status: 'unavailable' } | همان کادر محدود، نشانهٔ نوع (تصویر، ویدئو، چندرسانهای با تعداد)، «رسانه ذخیره نشده است» و پیوند «مشاهده در منبع» با sourceUrl |
| در منبع رسانه ندارد (اغلب تلگرام و X) | بدون media | هیچ کادری؛ کارت متنی فشرده میماند |
unavailable یعنی «ذخیره نشده»؛ وضعیت جدیدی لازم نیست، چون مبدلها همین معنا را از قبل به آن نگاشت میکنند و نشانیای
که resolveSrc رد کند هم یعنی نسخهای از رسانه نزد ما نیست. failed و expired معنای خودشان را دارند: رسانه را داشتیم و
بارگذاری نشد یا منقضی شد؛ نشانهٔ هشدار یا زمان دارند و هیچکدام شبیه حالت ذخیرهنشده نیست.

import { MediaFrame, type SocialMedia } from '@partodata/ui/social'
const media: SocialMedia = {
"kind": "image",
"src": "https://ui.partodata.com/instagram-posts/images/image%204x5.png",
"width": 896,
"height": 1152,
"status": "unavailable"
}
export function MediaFrameExample() {
return (
<MediaFrame
media={media}
sourceUrl="https://www.instagram.com/p/X1/"
/>
)
}رسانهٔ بدون ابعاد
API جستوجوی محتوا برای هر پست فقط thumbnailUrl میفرستد و عرض و ارتفاع ندارد، پس fromSearchContent به رسانه ابعادی
نمیدهد و قاب کادر جایگزین را میگیرد: مربع. در card این یعنی قابی به عرض ستون و حداکثر 500 پیکسل ارتفاع که رسانه کامل
در آن است؛ تصویر افقی 16:9 بهجای پر کردن عرض، بالا و پایینش نوار محو میگیرد. در details کادر مربع است. row و tile
کادر ثابت دارند و تفاوتی نمیکنند. هیچوقت چیزی بریده نمیشود و صفحه هم بعد از بارگذاری جابهجا نمیشود.
برای کادر درست، ابعاد را در مبدل با گزینهٔ mediaSize بدهید: از پراکسی رسانه، از جدول ابعادی که بر اساس نشانی نگه
میدارید، یا از خود API وقتی ابعاد تصویر بندانگشتی را بفرستد. روش کار در
مدل محتوای اجتماعی است. در هر ردیف پیشنمایش، قاب اول (سمت راست) همان
ردیف API بدون ابعاد است و قاب دوم همان ردیف با mediaSize:




ویدئو
ویدئوویدئو و صوت
ویدئو در card، tile و row با پوستر، نشانهٔ پخش و مدت نمایش داده میشود و خود فایل بارگذاری نمیشود؛ در details
پخشکنندهٔ واقعی دارد. ویدئوی بدون پوستر اولین قاب خودش را نشان میدهد، که یعنی بارگذاری خود فایل؛ برای همین فقط وقتی قاب
به محدودهٔ دید نزدیک شود (یا با priority) بارگذاری میشود و تا آن زمان کادر خنثی با نشانهٔ پخش است. هر جا ممکن است
poster بدهید. مدت صفر یا منفی نمایش داده نمیشود. مدت در گوشهٔ پایینِ سمت پایان صفحه است (در صفحهٔ راستبهچپ پایین
چپ)، پس با جایگاه aside کاشی در گوشهٔ شروع برخورد نمیکند. صوت در کارت یک نوار کوتاه است و در جزئیات پخشکننده دارد.
راهنمای استفاده
بکنید
widthوheightرسانه را هر جا معلوم است در مبدل پر کنید تا کادر از ابتدا درست باشد. ردیف API جستوجوی محتوا آنها را ندارد: با گزینهٔmediaSizeدرfromSearchContentبدهید؛ بدون آن هر مورد کادر مربع میگیرد.- برای ویدئو
posterبدهید. برای تصویر، اگر نسخهٔ کوچک آن را دارید، آن را هم درposterبگذارید: ردیف و کاشی همان نسخهٔ کوچک را بارگذاری میکنند و کارت و جزئیات تصویر کامل را. - برای چند مورد اول صفحه
priorityبگذارید و برای بقیه نه. - پراکسی و امضای نشانی را یک بار با
SocialMediaProviderانجام دهید، نه با ساختن نشانی در هر صفحه.
نکنید
- تصویر را با
object-coverیا کادر ثابت خودتان در کارت نبرید. - فهرست کارتها را در تمام عرض صفحه نچینید: در ستون 1500 پیکسلی هر تصویر به سقف 500 پیکسل میرسد و دو طرفش نوار محو بزرگ میماند. جای فهرست تکستونی، ستون خبرخوان (حدود 680 پیکسل) است.
- وضعیت رسانه را با جزء دیگری نسازید؛
statusرا تنظیم کنید.
Props
MediaFrame
SocialMediaProvider
نوع ورودی برای کامپوننتی که MediaFrame را در بر میگیرد
MediaFrameProps همان چیزی است که MediaFrame میپذیرد: ویژگیهای مشترک (MediaFrameBaseProps، جدول بالا) بهاضافهٔ
ویژگیهای یک چیدمان (MediaFrameLayoutProps). کامپوننتی که MediaFrame را در بر میگیرد ورودیاش را با MediaFrameProps
تعریف کند، تا همان قاعدهها (مثلاً density فقط در row) برای آن هم برقرار بماند:
import { MediaFrame, type MediaFrameProps } from '@partodata/ui/social'
export function PostMedia(props: MediaFrameProps) {
return <MediaFrame {...props} />
}برای حذف یک ویژگی، آن را از MediaFrameBaseProps حذف کنید و MediaFrameLayoutProps را دوباره اضافه کنید
(Omit<MediaFrameBaseProps, 'media'> & MediaFrameLayoutProps)؛ Omit روی خود MediaFrameProps چیدمانها را در هم
میریزد و دادن نتیجهاش به MediaFrame کامپایل نمیشود.
دسترسیپذیری
- تصویر بدون
altتزئینی است؛ وقتی متن پست محتوا را میگوید همین درست است. برای اینفوگرافی متن جایگزین بدهید. - نسخهٔ محوشدهٔ پسزمینه و نشانهٔ پخش از درخت دسترسیپذیری حذفاند؛ ویدئو با متن پنهان «ویدئو، مدت» اعلام میشود.
- هر وضعیت یک نشانهٔ نامدار (
role="img") دارد، پس صفحهخوان میگوید رسانه هست ولی بارگذاری نشده است. - دکمههای «تلاش دوباره» و «نمایش محتوای حساس» و پیوند «مشاهده در منبع» کلیک و کلیدهای Enter و Space را به کارت بیرونی نمیرسانند؛ Escape و کلیدهای جهت به فهرست بیرونی میرسند. پیوند منبع در زبانهٔ تازه باز میشود.
- پس از «تلاش دوباره» یا «نمایش»، دکمه حذف میشود و فوکوس به خود رسانه (در جزئیات، به پخشکننده) میرود، نه به ابتدای صفحه.
- ویدئوی حساس در جزئیات تا پیش از «نمایش» کنترل پخش ندارد و از ترتیب Tab بیرون است (
inert).
کامپوننتهای مرتبط
- SocialText — متن همان پست؛ کنار بندانگشتی ردیف با حداکثر دو یا سه خط.
- MetricGroup — شاخصهای پست زیر رسانه، با «—» برای مقدار نامعلوم.
- مدل محتوای اجتماعی — شکل
SocialMedia، مبدلهایی که وضعیت رسانه را پر میکنند و گزینهٔmediaSizeبرای ابعادی که API نمیفرستد.