diff --git a/src/components/posts/ExpandableCaption.tsx b/src/components/posts/ExpandableCaption.tsx
index e64280e..6a41c82 100644
--- a/src/components/posts/ExpandableCaption.tsx
+++ b/src/components/posts/ExpandableCaption.tsx
@@ -77,9 +77,10 @@ export default function ExpandableCaption({
<>
{body.trim() ? (
diff --git a/src/components/posts/ReelsPostActions.tsx b/src/components/posts/ReelsPostActions.tsx
index 6d7ca9f..e63868f 100644
--- a/src/components/posts/ReelsPostActions.tsx
+++ b/src/components/posts/ReelsPostActions.tsx
@@ -37,6 +37,10 @@ interface ReelsPostActionsProps {
/** وقتی onCommentClick پاس داده نشه، این کامپوننت خودش CommentsModal رو مدیریت میکنه —
* والد (ReelsPostCard) برای مخفیکردن نوار پیشرفت ویدیو حین بازبودنِ این مودال باید بدونه */
onCommentsModalOpenChange?: (open: boolean) => void;
+ /** فاصلهی px ستون اکشنها از پایینِ کارت — والد (ReelsPostCard) این رو از رویِ خطِ
+ * اولِ کپشنِ واقعی اندازه میگیره تا دکمهی جمعشونده همیشه روبروش بشینه؛ نبودش
+ * (postPage یا قبل از اولین اندازهگیری) یعنی مقدارِ پیشفرضِ کلاسِ bottom-36 */
+ columnBottom?: number;
}
function ReelsProfileFollowButton({
@@ -118,12 +122,15 @@ function ReelsStoryShareButton({
className="inline-flex shrink-0 items-center justify-center disabled:opacity-60"
aria-label={t("posts.addToStory")}
>
+ {/* اندازه و رنگ دقیقاً هماندازهی بقیهی آیکونهای ستون اکشنها (reelsIconSize=md:
+ w-7/28px + همون فیلترِ invert brightness-125) — قبلاً ۳۶px بود، هماندازهی
+ بقیه نبود */}
@@ -139,6 +146,7 @@ export default function ReelsPostActions({
sharingStory = false,
onShareToStory,
onCommentsModalOpenChange,
+ columnBottom,
}: ReelsPostActionsProps) {
const { t } = useTranslation("common");
const { user_id, user_name } = postData;
@@ -286,6 +294,12 @@ export default function ReelsPostActions({
const reelsActions = (
<>
+ {onShareToStory ? (
+
+ ) : null}
- {onShareToStory ? (
-
- ) : null}
+
{/* دکمهی جمعشونده همیشه باید آخرین فرزندِ این ستون باشه (نه هرچیزِ دیگهای زیرش)
— این ستون absolute + bottom-36 هست، پس لبهی پایینِ خودِ ستون همیشه ثابته،
اما وقتی فرزندی که زیرِ دکمهی toggle قرار داره (مثلاً منوی سهنقطه) شرطی
diff --git a/src/components/posts/ReelsPostCard.tsx b/src/components/posts/ReelsPostCard.tsx
index ceedc38..d0468b5 100644
--- a/src/components/posts/ReelsPostCard.tsx
+++ b/src/components/posts/ReelsPostCard.tsx
@@ -120,6 +120,23 @@ export default function ReelsPostCard({
useEffect(() => {
setCaptionExpanded(false);
}, [postData._id]);
+
+ useEffect(() => {
+ const captionEl = captionRef.current;
+ const containerEl = containerRef.current;
+ // اگه بلوکِ کپشن الان mount نیست (کپشنِ خالی، یا chrome/کامنتها مخفیش کرده)، آخرین
+ // مقدارِ اندازهگیریشده رو نگه میداریم تا با جمعکردنِ آیکونها ستون نپره
+ if (!captionEl || !containerEl) return;
+ const update = () => {
+ const containerRect = containerEl.getBoundingClientRect();
+ const captionRect = captionEl.getBoundingClientRect();
+ setActionsColumnBottom(containerRect.bottom - captionRect.top);
+ };
+ update();
+ const ro = new ResizeObserver(update);
+ ro.observe(captionEl);
+ return () => ro.disconnect();
+ }, [captionBody, captionLinks, captionExpanded]);
const [imageLoading, setImageLoading] = useState(() => (files?.length ?? 0) > 0);
const [commentsOpen, setCommentsOpen] = useState(false);
// وقتی postPage=true، کامنتها توی CommentsModal جدا (نه شیت این کامپوننت) باز میشه
@@ -137,6 +154,15 @@ export default function ReelsPostCard({
const videoRef = useRef(null);
const containerRef = useRef(null);
+ const captionRef = useRef(null);
+ // طبق خواستهی کاربر: دکمهی جمعشوندهی ستونِ اکشنها (ReelsPostActions) باید همیشه
+ // دقیقاً روبروی خطِ اولِ کپشن باشه — چون طولِ کپشن/فونت فرق میکنه، بهجای عددِ ثابتِ
+ // حدسی (bottom-36)، فاصلهی واقعیِ لبهی پایینِ کارت تا لبهی بالای بلوکِ کپشن رو
+ // اندازه میگیریم (هر دو نسبت به همون container، چون وقتی کامنتها بستهست بلوکِ
+ // مدیا هماندازهی کاملِ container ـه)
+ const [actionsColumnBottom, setActionsColumnBottom] = useState(
+ null,
+ );
const viewStartedAtRef = useRef(null);
const watchCompleteTrackedRef = useRef(false);
const holdTimerRef = useRef(null);
@@ -461,7 +487,11 @@ export default function ReelsPostCard({
alt=""
fill
sizes="100vw"
- className="object-contain"
+ // object-bottom: طبق خواستهی کاربر، لبهی پایینِ محتوای ویدیو باید همیشه
+ // دقیقاً روی لبهی پایینِ کادر بشینه (نه وسطچین) — تا صرفنظر از نسبتِ
+ // ابعادِ صفحهنمایشِ گوشی، این خط ثابت بمونه؛ پوستر هم باید با همون
+ // لنگرگاه نمایش داده بشه، وگرنه لحظهی لود شدنِ ویدیو یه پرش دیده میشه
+ className="object-contain object-bottom"
priority={isActive || preloadPriority === "nearby"}
draggable={!allowSave ? false : undefined}
onContextMenu={
@@ -478,7 +508,7 @@ export default function ReelsPostCard({
preload={videoPreload}
controlsList="nodownload"
className={cn(
- "h-full w-full object-contain",
+ "h-full w-full object-contain object-bottom",
videoPoster && !videoReady && "opacity-0"
)}
onClick={handleVideoClick}
@@ -691,7 +721,7 @@ export default function ReelsPostCard({
{(captionBody || captionLinks) && (
-
+
setCommentsOpen(true) : undefined
}
onCommentsModalOpenChange={setCommentsModalOpen}
+ columnBottom={actionsColumnBottom ?? undefined}
/>
)}