From ab98f21aac0140d9e671e4684fb7a2f3905d2272 Mon Sep 17 00:00:00 2001 From: vsecoder Date: Sat, 18 Apr 2026 21:35:07 +0300 Subject: [PATCH] fix(feed): stack header + full-width content instead of avatar-sibling column MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The previous layout put body text, attachments and action row inside a column next to the avatar. Two recurring bugs came from that: 1. The column's width = screen - 16 - 44 - 10 - 16 = screen - 86px. Long text or attachments computed against that narrower width, and on a few RN builds the measurement was off enough that text visibly ran past the card's right edge. 2. The column visually looked weird: a photo rendered only 3/4 of the card width because the avatar stole 54px on the left. Fix: make the card a vertical stack. ┌─────────────────────────────────────────┐ │ [avatar] [name · time] [menu] │ ← HEADER row ├─────────────────────────────────────────┤ │ body text, full card width │ ← content column │ [attachment image, full card width] │ │ [action row, full card width] │ └─────────────────────────────────────────┘ Now body and media always occupy the full card width (paddingLeft:16 paddingRight:16 from the outer View), long lines wrap inside that, and the earlier overflow-tricks / width-100% / paddingRight-4 band-aids aren't needed. Removed them. Header row is unchanged structurally (avatar + name-row Pressable + menu button) — just lifted into a dedicated View so the content column below starts at the left card edge instead of alongside the avatar. Co-Authored-By: Claude Opus 4.7 (1M context) --- client-app/components/feed/PostCard.tsx | 124 +++++++++++------------- 1 file changed, 57 insertions(+), 67 deletions(-) diff --git a/client-app/components/feed/PostCard.tsx b/client-app/components/feed/PostCard.tsx index 1778c21..6ffd902 100644 --- a/client-app/components/feed/PostCard.tsx +++ b/client-app/components/feed/PostCard.tsx @@ -190,86 +190,80 @@ function PostCardInner({ post, likedByMe, onStatsChanged, onDeleted, compact }: we're not relying on it here either. Tap handling lives on the content-column Pressable (covers ~90% of the card area) plus a separate Pressable around the avatar. */} + {/* Card = vertical stack: [HEADER row with avatar+name+time] / + [FULL-WIDTH content column with body/image/actions]. Putting + content under the header (rather than in a column next to the + avatar) means body text and attachments occupy the full card + width — no risk of the text running next to the avatar and + clipping off the right edge. */} - {/* Avatar — own tap target (opens author profile). Explicit width - on the wrapper (width:44) so the flex-row sibling below computes - its remaining space correctly. */} - - - + {/* ── HEADER ROW: [avatar] [name · time] [menu] ──────────────── */} + + + + - {/* Content column. Pressable so the card body is tappable → - detail; onLongPress routes to the context menu. overflow: - 'hidden' prevents unbreakable tokens from drawing past the - right edge. */} + {/* Name + time take all remaining horizontal space in the + header, with the name truncating (numberOfLines:1 + + flexShrink:1) and the "· + + {/* ── CONTENT (body, attachment, actions) — full card width ──── */} ({ - flex: 1, - marginLeft: 10, - minWidth: 0, + marginTop: 8, overflow: 'hidden', opacity: pressed ? 0.85 : 1, })} > - {/* Header row — name + time on ONE line. - Two siblings: the author-link Pressable (flex:1, row, so it - expands; name inside gets numberOfLines:1 + flexShrink:1 so - it truncates instead of wrapping) and the "·