mail list redesign, folder actions, empty-folder, unread badges & empty-state art

Frontend:
- Redesign the mail list rows (avatar + sender + subject/snippet + right rail),
  even-spaced attachment/pin/archive/trash icons, hover-reveal actions, pink
  always-on pin, monocolor paperclip, row gaps, wider sender-subject gap.
- Sidebar folder badges: Inbox unread + Drafts counts (live via WS + mutations).
- Trash/Spam/Archive: hover Restore icon (replaces Archive), permanent delete in
  Trash; "Empty trash" / "Empty spam" buttons on the sort bar.
- Reading pane empty state: email illustration above an enlarged
  "Select a conversation".
- Search field clear (X) button; mark-read after a 4s dwell instead of instantly.

Backend:
- GET /api/mailboxes/counts (inbox unread + drafts) for the sidebar badges.
- POST /api/folders/{special}/empty + empty_folder_job to permanently clear a
  Trash/Spam/Archive folder (server EXPUNGE + DB rows + thread cleanup).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01U72FZiF1W1pb8XxyWBTREA
This commit is contained in:
2026-07-22 07:40:29 +02:00
co-authored by Claude Opus 4.8
parent d650f16feb
commit fdb6ee002e
22 changed files with 1758 additions and 68 deletions
+4
View File
@@ -12,6 +12,7 @@ export const en = {
"common.remove": "Remove",
"common.edit": "Edit",
"common.close": "Close",
"common.clear": "Clear",
"common.back": "Back",
"common.next": "Next",
"common.signOut": "Sign out",
@@ -78,6 +79,9 @@ export const en = {
"mail.unpin": "Unpin",
"mail.delete": "Delete",
"mail.restore": "Restore",
"mail.emptyTrash": "Empty trash",
"mail.emptySpam": "Empty spam",
"mail.emptyConfirm": "Permanently delete everything in this folder? This can't be undone.",
"mail.loadFailed": "Couldn't load this message.",
"mail.imagesBlocked": "Images from this sender are blocked.",
"mail.loadImages": "Load images",