From 13bafa5747cc58c76778a3b4d0a4efb5f4295aa9 Mon Sep 17 00:00:00 2001 From: Arnas Donauskas Date: Sun, 31 May 2026 12:28:49 +0300 Subject: [PATCH] fix(inbox): reply quote no longer overflows or single-lines (#165) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A long reply quote was forcing the entire 3-panel inbox layout wider, pushing the contact sidebar off-screen and making the page horizontally scrollable. Two root causes (both correctly diagnosed in the issue by @tekrexllp): 1. ReplyQuote applied `truncate` to the preview text, which sets `white-space: nowrap`. Long previews became one impossibly-wide line instead of wrapping. 2. The flex chain from MessageBubble outward (MessageActions → middle-panel wrapper → page) had no `min-w-0` on its flex children. Default `min-width: auto` means a flex child grows to its content's natural width, so the long quote propagated all the way up to the inbox-page flex container and pushed the contact sidebar past the viewport. Fix: - ReplyQuote preview now uses `whitespace-pre-wrap break-words` instead of `truncate`. The author label stays single-line (it's a name, ellipsis is right for it). `overflow-hidden` on the inner text container as belt-and-braces. - MessageActions' .group/actions wrapper gets `min-w-0` so the `max-w-[75%]` cap actually holds even with wide content. - inbox/page.tsx middle-panel wrapper gets `min-w-0` so the MessageThread can shrink below its natural content width when the conversation list and contact sidebar are also flexing. Audited the other 38 `truncate` usages across the codebase — they're all on intentionally single-line content (contact names, file paths, last-message previews in lists, headers, node summaries) where ellipsis is the right behavior. ReplyQuote was the only multi-line `truncate` misuse. Reported and diagnosed by @tekrexllp in #165. Co-Authored-By: Claude Opus 4.7 (1M context) --- src/app/(dashboard)/inbox/page.tsx | 10 ++++++++-- src/components/inbox/message-actions.tsx | 7 ++++++- src/components/inbox/reply-quote.tsx | 13 +++++++++++-- 3 files changed, 25 insertions(+), 5 deletions(-) diff --git a/src/app/(dashboard)/inbox/page.tsx b/src/app/(dashboard)/inbox/page.tsx index ab50293..21143a2 100644 --- a/src/app/(dashboard)/inbox/page.tsx +++ b/src/app/(dashboard)/inbox/page.tsx @@ -530,10 +530,16 @@ export default function InboxPage() { {/* Center panel: Message thread. Hidden on mobile when no conversation is selected so the list can occupy the full width. Always visible on lg+ - (shows its own empty-state if no thread is picked yet). */} + (shows its own empty-state if no thread is picked yet). + + `min-w-0` is load-bearing: without it, a single wide piece + of content inside the thread (long quote preview, very + long URL in a message body) forces the flex child past + its share and pushes the contact-sidebar panel off-screen + on the right. Issue #165. */}
diff --git a/src/components/inbox/message-actions.tsx b/src/components/inbox/message-actions.tsx index bd63f6f..4e23ecf 100644 --- a/src/components/inbox/message-actions.tsx +++ b/src/components/inbox/message-actions.tsx @@ -85,7 +85,12 @@ export function MessageActions({ onContextMenu={handleContextMenu} onBlur={() => setTouchOpen(false)} > -
+ {/* `min-w-0` lets this flex child actually respect the 75% cap. + * Default `min-width: auto` lets content (a long quote preview, + * an unbroken URL) push past the cap and shove the row past + * 100%, which used to bleed across into the contact-sidebar + * area. See issue #165. */} +
{children}
-
+
{authorLabel}
-
{preview}
+ {/* Wrap the preview instead of truncating to a single line. + * `truncate` (white-space: nowrap) forced the quote onto one + * impossibly-wide line and — because the parent flex chain + * lacked `min-w-0` at every step — pushed the entire inbox + * layout wider, shoving the contact sidebar off-screen. + * `break-words` also wraps long URLs that have no whitespace + * to break on. Issue #165. */} +
+ {preview} +
{onDismiss && (