From 68bcce809124237e356c7f03b0f554920aed7883 Mon Sep 17 00:00:00 2001 From: zxyszx <299979470+zxyszx@users.noreply.github.com> Date: Sun, 2 Aug 2026 10:03:34 +0800 Subject: [PATCH] fix: tighten mail layout responsiveness --- apps/web/src/index.css | 6 +- apps/web/src/pages/mail.tsx | 169 ++++++++++++++++++++---------------- 2 files changed, 97 insertions(+), 78 deletions(-) diff --git a/apps/web/src/index.css b/apps/web/src/index.css index cde243d..b40abde 100644 --- a/apps/web/src/index.css +++ b/apps/web/src/index.css @@ -44,7 +44,11 @@ font-family: ui-sans-serif, -apple-system, BlinkMacSystemFont, "Segoe UI", "PingFang SC", "Microsoft YaHei", "Helvetica Neue", Arial, sans-serif; font-size: 13px; } - html, body, #root { min-height: 100%; } + html, body, #root { + min-height: 100%; + min-width: 0; + width: 100%; + } html.dark { color-scheme: dark; } .dark { diff --git a/apps/web/src/pages/mail.tsx b/apps/web/src/pages/mail.tsx index f80f4cd..42b457c 100644 --- a/apps/web/src/pages/mail.tsx +++ b/apps/web/src/pages/mail.tsx @@ -89,6 +89,19 @@ const filterLabels: Record = { const emptyAdvancedSearch: AdvancedMailSearch = { from: "", to: "", subject: "", startDate: "", endDate: "", hasAttachments: false, unread: false, starred: false } const emptyAdvancedSearchDraft: AdvancedMailSearchDraft = { ...emptyAdvancedSearch } const mailboxSelectionStorageVersion = "2" +const mailCompactBreakpoint = 1024 + +function useMaxViewportWidth(maxWidth: number) { + const [matches, setMatches] = React.useState(false) + React.useEffect(() => { + const media = window.matchMedia(`(max-width: ${maxWidth - 1}px)`) + const sync = () => setMatches(media.matches) + media.addEventListener("change", sync) + sync() + return () => media.removeEventListener("change", sync) + }, [maxWidth]) + return matches +} export function MailPage() { const qc = useQueryClient() @@ -119,6 +132,8 @@ export function MailPage() { const [language, setLanguage] = useLanguage() const [displayMode] = useDisplayMode() const isMobile = useIsMobile() + const isNarrowMailViewport = useMaxViewportWidth(mailCompactBreakpoint) + const compactMailLayout = isMobile || isNarrowMailViewport || displayMode === "compact" const [refreshing, setRefreshing] = React.useState(false) const [autoRefreshing, setAutoRefreshing] = React.useState(false) const [lastAutoRefreshAt, setLastAutoRefreshAt] = React.useState(null) @@ -1052,7 +1067,7 @@ export function MailPage() { } const sidebarContent = ( - + -
+
{!sidebarCollapsed && !isAllMailboxSelected && ( - )}
{canSendMail && ( - @@ -1108,7 +1123,7 @@ export function MailPage() { openExternalFolder(account, item.name)} > {folderIcons[item.role.toLowerCase()] || } @@ -1214,7 +1229,7 @@ export function MailPage() { { if (!labelEditMode) openLabel(label.id) }} > {sidebarCollapsed ? ( @@ -1323,7 +1338,7 @@ export function MailPage() { ) : mailView === "scheduled" && canScheduleMail ? ( ) : mailView === "sendQueue" && canViewSendQueue ? ( ) : mailView === "sendQueue" ? ( - ) : isMobile || displayMode === "compact" ? ( + ) : compactMailLayout ? ( {selectedLabel.name} : undefined} @@ -1402,12 +1417,12 @@ export function MailPage() { /> ) : ( - +
-
+
- - setQuery(e.target.value)} onKeyDown={handleSearchKeyDown} placeholder="搜索发件人、主题、内容..." className="h-10 rounded-lg bg-background pl-9 text-sm shadow-none" /> + + setQuery(e.target.value)} onKeyDown={handleSearchKeyDown} placeholder="搜索发件人、主题、内容..." className="h-9 rounded-md bg-background pl-8 text-[13px] shadow-none" />
)} -
+
快捷筛选 {(["attachments", "starred", "recent7"] as MailFilter[]).map((value) => (
-
-
+
+
toggleCompactSelectAll(value === true)} /> - +
-
-

{mailView === "label" && selectedLabel ? selectedLabel.name : viewTitle}

+
+

{mailView === "label" && selectedLabel ? selectedLabel.name : viewTitle}

- - {canOrganizeMail && } - + {canOrganizeMail && } +
-
+
{selectedCountOnPage > 0 && canOrganizeMail && } - - + +
@@ -1486,7 +1501,7 @@ export function MailPage() { - +
{!selectedId && (
@@ -1532,7 +1547,7 @@ export function MailPage() { return (
- + {isMobile ? (
{!selectedId && ( @@ -1560,13 +1575,13 @@ export function MailPage() {
{contentView}
) : ( - - + + {sidebarContent} - -
+ +
{contentView}
@@ -2236,11 +2251,11 @@ function BulkActionMenu({ pending, onAction }: { pending: boolean; onAction: (ac return ( - - + onAction("read")}>标为已读 onAction("unread")}>标为未读 onAction("star")}>添加星标 @@ -2592,23 +2607,23 @@ function CompactMailView({ } return ( -
-
-
+
+
+
onSelectAll(value === true)} /> -
+
{icon} {title}
-
+
{selectedIds.length > 0 ? ( <> - 已选 {selectedIds.length} 封 + 已选 {selectedIds.length} 封 {canOrganize && } ) : ( -
{messages.length} / {total} 封
+
{messages.length} / {total} 封
)}
@@ -2900,7 +2915,7 @@ function CompactMessageRow({ message, active, checked, scheduled, onCheckedChang const hiddenLabelCount = Math.max((message.labels?.length || 0) - visibleLabels.length, 0) const senderName = senderDisplayName(message) return ( -
+
onCheckedChange(value === true)} onClick={(event) => event.stopPropagation()} className="mt-0.5 shrink-0 sm:mt-0" /> {message.isRead ? ( @@ -2913,8 +2928,8 @@ function CompactMessageRow({ message, active, checked, scheduled, onCheckedChang
{senderName}
{formatDate(message.receivedAt)} - {canOrganize && }
@@ -2930,8 +2945,8 @@ function CompactMessageRow({ message, active, checked, scheduled, onCheckedChang
{formatDate(message.receivedAt)}
- {canOrganize && }
) @@ -2980,8 +2995,8 @@ function AccountHeader({ collapsed, name, email, darkMode, language, onToggleThe if (collapsed) { return (
- - {accountInitial(displayName, email)} + + {accountInitial(displayName, email)}
) @@ -2989,20 +3004,20 @@ function AccountHeader({ collapsed, name, email, darkMode, language, onToggleThe return (
- - {accountInitial(displayName, email)} + + {accountInitial(displayName, email)} -
-
{displayName}
+
+
{displayName}
- - @@ -3015,8 +3030,8 @@ function AccountHeader({ collapsed, name, email, darkMode, language, onToggleThe ))} -
@@ -3039,17 +3054,17 @@ function MailboxSwitcher({ collapsed, mailboxes, selectedMailboxId, selectedMail return ( { if (!open) setMailboxQuery("") }}> - - + {mailboxes.length > 0 && (
setMailboxQuery(event.target.value)} onKeyDown={(event) => event.stopPropagation()} placeholder="搜索邮箱..." - className="h-9 rounded-md bg-background px-2 text-sm shadow-none" + className="h-8 rounded-md bg-background px-2 text-[13px] shadow-none" />
)} {mailboxes.length === 0 && 没有可用邮箱} {mailboxes.length > 0 && showAllMailboxOption && ( - onSelect("all")} className={cn("h-8 gap-2 rounded-sm px-2 text-sm font-normal", isAllSelected && "bg-accent text-accent-foreground")}> - + onSelect("all")} className={cn("h-8 gap-2 rounded-sm px-2 text-[13px] font-normal", isAllSelected && "bg-accent text-accent-foreground")}> + 全部邮箱 )} {filteredMailboxes.map((mailbox) => ( - onSelect(mailbox.id)} className={cn("h-8 min-w-0 gap-2 rounded-sm px-2 text-sm font-normal", !isAllSelected && selectedMailbox?.id === mailbox.id && "bg-accent text-accent-foreground")}> - + onSelect(mailbox.id)} className={cn("h-8 min-w-0 gap-2 rounded-sm px-2 text-[13px] font-normal", !isAllSelected && selectedMailbox?.id === mailbox.id && "bg-accent text-accent-foreground")}> + {mailbox.address} ))} @@ -3301,8 +3316,8 @@ function MessageRow({ const visibleLabels = (message.labels || []).slice(0, 2) const hiddenLabelCount = Math.max((message.labels?.length || 0) - visibleLabels.length, 0) const senderName = senderDisplayName(message) - return
-
+ return
+
-
{senderName}
+
{senderName}
{canOrganize && }
{formatDate(message.receivedAt)}
- {message.subject || "无主题"} + {message.subject || "无主题"} {scheduled && 已定时} {visibleLabels.map((label) => )} {hiddenLabelCount > 0 && +{hiddenLabelCount}}