From df8d04e233e4c1c05aa11a4a469310143e505083 Mon Sep 17 00:00:00 2001 From: Linus Rath <139418639+rathlinus@users.noreply.github.com> Date: Fri, 24 Apr 2026 19:31:38 +0200 Subject: [PATCH] fix: restore broken viewer toolbar actions and improve mobile menu #220 --- app/[locale]/page.tsx | 18 +- components/email/email-viewer.tsx | 274 +++++++++++++++++------------- 2 files changed, 160 insertions(+), 132 deletions(-) diff --git a/app/[locale]/page.tsx b/app/[locale]/page.tsx index 197a65a2..060e4603 100644 --- a/app/[locale]/page.tsx +++ b/app/[locale]/page.tsx @@ -1295,15 +1295,11 @@ export default function Home() { }; // Handle back navigation from viewer on mobile. - // Delegate to the browser history stack so this button is equivalent to - // the OS back button / mouse back button - popstate then restores the - // previous snapshot via handleNavRestore. The viewer is only reachable - // from a state that pushed history, so back() always lands on an app entry. + // Reset to list state directly. We can't just call window.history.back() + // because the nav hook pushes a new entry for every email the user opens, + // so history.back() would pop to the previous email rather than the list. + // The OS / hardware back button is still wired through popstate → handleNavRestore. const handleMobileBack = () => { - if (typeof window !== 'undefined') { - window.history.back(); - return; - } if (conversationThread) { setConversationThread(null); setConversationEmails([]); @@ -1934,12 +1930,12 @@ export default function Home() { onReply={handleReply} onReplyAll={handleReplyAll} onForward={handleForward} - onDelete={handleDelete} + onDelete={() => handleDelete()} onArchive={() => handleArchive()} onToggleStar={handleToggleStar} onSetColorTag={handleSetColorTag} - onMarkAsSpam={handleMarkAsSpam} - onUndoSpam={handleUndoSpam} + onMarkAsSpam={() => handleMarkAsSpam()} + onUndoSpam={() => handleUndoSpam()} onMarkAsRead={async (emailId, read) => { if (client) { await markAsRead(client, emailId, read); diff --git a/components/email/email-viewer.tsx b/components/email/email-viewer.tsx index f66d0f21..689f405a 100644 --- a/components/email/email-viewer.tsx +++ b/components/email/email-viewer.tsx @@ -3436,70 +3436,172 @@ export function EmailViewer({ moreMenuOpen ? "translate-x-0" : "translate-x-full" )}>
- {t('more_actions')} - + ) : ( + {t('more_actions')} + )} +
- - {/* Move to folder */} - {moveTree.length > 0 && onMoveToMailbox && ( + {moreMenuSub === null && ( <> + + {/* Move to folder (opens sub-view) */} + {moveTree.length > 0 && onMoveToMailbox && ( + + )} + {/* Tag (opens sub-view) */} + {colorOptions.length > 0 && ( + + )} + {/* Spam */} + {(onMarkAsSpam || onUndoSpam) && ( + + )} + {/* Toggle read state */} + + + + {effectiveEmailContent.isHtml && ( + + )}
-
{t('move_to')}
- {(() => { - const renderMobileNodes = (nodes: MailboxNode[], depth = 0) => { - return nodes.map((node) => { - const Icon = getMoveMailboxIcon(node.role); - const isTarget = moveTargetIds.has(node.id); - return ( -
- {isTarget ? ( - - ) : ( -
- - {node.name} -
- )} - {node.children.length > 0 && renderMobileNodes(node.children, depth + 1)} -
- ); - }); - }; - return renderMobileNodes(moveTree); - })()} -
+ + + {onShowShortcuts && ( + + )} )} - {/* Tags */} - {colorOptions.length > 0 && ( + {moreMenuSub === 'move' && moveTree.length > 0 && onMoveToMailbox && (() => { + const renderMobileNodes = (nodes: MailboxNode[], depth = 0) => { + return nodes.map((node) => { + const Icon = getMoveMailboxIcon(node.role); + const isTarget = moveTargetIds.has(node.id); + return ( +
+ {isTarget ? ( + + ) : ( +
+ + {node.name} +
+ )} + {node.children.length > 0 && renderMobileNodes(node.children, depth + 1)} +
+ ); + }); + }; + return renderMobileNodes(moveTree); + })()} + {moreMenuSub === 'tag' && colorOptions.length > 0 && ( <> -
-
{t('tag')}
{colorOptions.map((option) => { const isActive = currentColors.includes(option.value); return ( )} -
)} - {/* Spam */} - {(onMarkAsSpam || onUndoSpam) && ( - - )} - {/* Toggle read state */} - - - - {effectiveEmailContent.isHtml && ( - - )} -
- - - {onShowShortcuts && ( - - )}
)}