From f0fddecd2e85a500dbb3c0807dd69801ebb7069e Mon Sep 17 00:00:00 2001 From: Nathan Daeila Date: Tue, 13 Oct 2026 00:09:56 -0700 Subject: [PATCH] Use the full width for message bodies on mobile (#112) * Use the full width for message bodies on mobile The reader indents the subject, sender row and body by the avatar column (pl-12/pl-16) at every width, which leaves a 64px gutter on a phone. Below the sm breakpoint the subject, body, attachments and the scheduled-send banner's wrapper now start at the page edge; wider screens are unchanged. * improve mobile layout for email content --------- Co-authored-by: Hieu Nguyen (Jack) --- .../(dashboard)/inbox/[messageId]/page.tsx | 42 +++++++++++++------ .../message-actions/message-actions.tsx | 14 ++----- .../messages/conversation-thread.tsx | 25 ++++++++--- src/lib/i18n/en.json | 2 + 4 files changed, 55 insertions(+), 28 deletions(-) diff --git a/src/app/(dashboard)/inbox/[messageId]/page.tsx b/src/app/(dashboard)/inbox/[messageId]/page.tsx index beee9b1..0ced9c1 100644 --- a/src/app/(dashboard)/inbox/[messageId]/page.tsx +++ b/src/app/(dashboard)/inbox/[messageId]/page.tsx @@ -54,6 +54,7 @@ export default function MessageDetailPage() { const [previewAttachment, setPreviewAttachment] = useState(null); const [threadExpanded, setThreadExpanded] = useState(false); + const [detailsOpen, setDetailsOpen] = useState(false); const [latestMessagesFirst] = useLatestMessagesFirst(); const { enabled: showFullRecipientAddresses } = useShowFullRecipientAddresses(); const { visible: messageListVisible } = useMessageListVisibility(); @@ -96,6 +97,7 @@ export default function MessageDetailPage() { useEffect(() => { setThreadExpanded(false); + setDetailsOpen(false); }, [messageId]); if (loading) { @@ -149,6 +151,11 @@ export default function MessageDetailPage() { const cloudAttachmentResult = extractCloudAttachments( bodyDisplay.latestContent, ); + const messageDate = (withTime: boolean) => scheduledAt + ? formatScheduledSendTime(scheduledAt, t) + : formatUserDate(message.createdAt, withTime + ? { month: "short", day: "2-digit", year: "numeric", hour: "2-digit", minute: "2-digit" } + : { month: "short", day: "2-digit", year: "numeric" }); return (<>
@@ -184,7 +191,7 @@ export default function MessageDetailPage() {
{!message.read && } -

+

{message.subject ?? t("list.noSubject")}

{/*
@@ -210,9 +217,9 @@ export default function MessageDetailPage() { expandedAll={threadExpanded} onExpandedAllChange={setThreadExpanded} /> -
+
-
+
{" "} - <{fromAddress}> + <{fromAddress}>

{t("source.to").toLowerCase()}{" "} @@ -247,6 +254,12 @@ export default function MessageDetailPage() { style={showFullRecipientAddresses ? "full" : "address"} />

+
+ {messageDate(false)} + +
{ccEntries.length > 0 && (

{t("message.cc")} @@ -260,11 +273,7 @@ export default function MessageDetailPage() {

-

- {scheduledAt - ? formatScheduledSendTime(scheduledAt, t) - : formatUserDate(message.createdAt, { month: "short", day: "2-digit", year: "numeric", hour: "2-digit", minute: "2-digit" })} -

+

{messageDate(true)}

threadMessage.id === message.id) || !thread.messages.some((threadMessage) => threadMessage.id !== message.id)} />
+ {detailsOpen && ( +
+
{t("source.from")}:
{fromName} <{fromAddress}>
+
{t("source.to")}:
{toEntries.join(", ")}
+
{t("message.date")}:
{messageDate(true)}
+
+ )}
- {scheduledAt &&
} -
+ {scheduledAt &&
} +
{htmlBody ? ( ) : ( @@ -292,7 +308,7 @@ export default function MessageDetailPage() { ))}
{cloudAttachmentResult.attachments.length > 0 && ( -
+

{t("message.cloudFiles", { count: cloudAttachmentResult.attachments.length })}

@@ -321,7 +337,7 @@ export default function MessageDetailPage() {
)} {attachments.length > 0 && ( -
+

{t("message.attachments", { count: attachments.length })}

diff --git a/src/components/message-actions/message-actions.tsx b/src/components/message-actions/message-actions.tsx index b885489..66ad508 100644 --- a/src/components/message-actions/message-actions.tsx +++ b/src/components/message-actions/message-actions.tsx @@ -261,16 +261,6 @@ export function MessageActions({ {isMobile && ( <> - + {canReplyAll && ( - + {attachments.length > 0 && } {formatUserDate(message.createdAt, { month: "short", day: "2-digit", year: "numeric", hour: "2-digit", minute: "2-digit" })} @@ -195,9 +196,23 @@ export function ConversationMessageCard({ ownAddresses={ownAddresses} starOnly={!expanded} /> +
+ {attachments.length > 0 && } + {formatUserDate(message.createdAt, { month: "short", day: "2-digit", year: "numeric" })} + +
+ {detailsOpen && ( +
+
{t("source.from")}:
{sender} <{senderEmail}>
+ {recipients &&
{t("source.to")}:
{recipients}
} +
{t("message.date")}:
{formatUserDate(message.createdAt, { month: "short", day: "2-digit", year: "numeric", hour: "2-digit", minute: "2-digit" })}
+
+ )}
{expanded && body && ( -
+
{body.html ? ( ) : ( diff --git a/src/lib/i18n/en.json b/src/lib/i18n/en.json index 8c0598d..776cd1b 100644 --- a/src/lib/i18n/en.json +++ b/src/lib/i18n/en.json @@ -76,6 +76,8 @@ "message.replyAll": "Reply all", "message.forward": "Forward", "message.showOriginal": "Show original", + "message.details": "Details", + "message.date": "Date", "message.blockContact": "Block contact", "message.star": "Star", "message.removeStar": "Remove star",