feat: mobile-responsive mail plugin UI

This commit is contained in:
Agent Zero
2026-07-15 17:53:56 +02:00
parent 57b6df5357
commit de74429f4e
7 changed files with 127 additions and 38 deletions
+81 -2
View File
@@ -69,6 +69,7 @@ export function MailPage() {
const [forwardMailState, setForwardMailState] = useState<Mail | null>(null);
const [downloadingAttachmentId, setDownloadingAttachmentId] = useState<string | null>(null);
const [searchQuery, setSearchQuery] = useState('');
const [activeView, setActiveView] = useState<'folders' | 'list' | 'detail'>('folders');
// Load accounts
const loadAccounts = useCallback(async () => {
@@ -168,6 +169,7 @@ export function MailPage() {
setMailsPage(1);
setSearchQuery('');
setSelectedMail(null);
setActiveView('list');
},
[folders],
);
@@ -175,6 +177,7 @@ export function MailPage() {
// Handle mail selection
const handleSelectMail = useCallback(
async (mail: Mail) => {
setActiveView('detail');
setLoadingMail(true);
try {
const detail = await getMail(mail.id);
@@ -435,8 +438,8 @@ export function MailPage() {
</div>
)}
{/* Three-pane layout with resizable panels */}
<div className="flex flex-1 overflow-hidden">
{/* Desktop: three-pane layout with resizable panels */}
<div className="hidden md:flex flex-1 overflow-hidden">
{/* Folder tree — resizable */}
<ResizablePanel
initialWidth={224}
@@ -495,6 +498,82 @@ export function MailPage() {
</ResizablePanel>
</div>
{/* Mobile: single-pane view switching */}
<div className="flex md:hidden flex-1 overflow-hidden flex-col">
{/* View 1: Folder tree */}
{activeView === 'folders' && (
<div className="flex-1 overflow-y-auto bg-white" data-testid="mobile-folder-pane">
<div className="p-3">
<MailFolderTree
accounts={accounts}
folders={folders}
selectedFolderId={selectedFolderId}
onSelect={handleSelectFolder}
loading={loadingFolders}
/>
</div>
</div>
)}
{/* View 2: Mail list */}
{activeView === 'list' && (
<div className="flex-1 overflow-y-auto bg-white" data-testid="mobile-list-pane">
<div className="flex items-center gap-2 px-3 py-2 border-b border-secondary-200 sticky top-0 bg-white z-10">
<button
onClick={() => setActiveView('folders')}
className="inline-flex items-center gap-1 px-2 py-1 rounded text-sm text-secondary-700 hover:bg-secondary-100 min-h-touch"
aria-label="Zurück zu Ordnern"
data-testid="mobile-back-to-folders"
>
<svg className="w-4 h-4" fill="none" viewBox="0 0 24 24" stroke="currentColor" aria-hidden="true">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M15 19l-7-7 7-7" />
</svg>
<span className="text-sm font-medium">Ordner</span>
</button>
</div>
<MailList
mails={mails}
selectedMailId={selectedMail?.id || null}
onSelectMail={handleSelectMail}
loading={loadingMails}
currentPage={mailsPage}
total={mailsTotal}
pageSize={PAGE_SIZE}
onPageChange={setMailsPage}
/>
</div>
)}
{/* View 3: Mail detail */}
{activeView === 'detail' && (
<div className="flex-1 overflow-y-auto bg-white" data-testid="mobile-detail-pane">
<div className="flex items-center gap-2 px-3 py-2 border-b border-secondary-200 sticky top-0 bg-white z-10">
<button
onClick={() => setActiveView('list')}
className="inline-flex items-center gap-1 px-2 py-1 rounded text-sm text-secondary-700 hover:bg-secondary-100 min-h-touch"
aria-label="Zurück zur Liste"
data-testid="mobile-back-to-list"
>
<svg className="w-4 h-4" fill="none" viewBox="0 0 24 24" stroke="currentColor" aria-hidden="true">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M15 19l-7-7 7-7" />
</svg>
<span className="text-sm font-medium">Zurück</span>
</button>
</div>
<MailDetail
mail={selectedMail}
loading={loadingMail}
onReply={handleReply}
onForward={handleForward}
onCreateEvent={handleCreateEvent}
onToggleFlag={handleToggleFlag}
onDownloadAttachment={handleDownloadAttachment}
downloadingAttachmentId={downloadingAttachmentId}
/>
</div>
)}
</div>
<ComposeModal
open={composeOpen}
mode={composeMode}