Reading pane layouts: Side, Bottom (under the list) and Off (single panel)

Choose in Settings > Appearance, or the list's ⋯ menu > Mailbox display (a
popover with three preview cards; picking one applies it and closes it).
Stored per device, like the theme; phones keep their own single panel.

- Side: the existing three columns.
- Bottom: the list above, the reading pane below, 45/55 until the 3px divider
  is dragged (height remembered). The pane's top bar takes the list filter
  bar's colour; the empty-pane picture shrinks to fit.
- Off: one panel. The list, until a conversation opens in its place with a
  Back button; bulk actions move to a bar above the list. This reuses the
  phone's list/pane switching with desktop styling.
- In Bottom and Off the side-panel toggle sits beside the search box (Off also
  keeps it in the conversation toolbar, since the list is hidden there).
- An expanded composer covers the reading pane in every arrangement: the lower
  pane under the list, the whole panel with the pane off.

Resizer gains a horizontal orientation; layoutDock takes the pane height.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-03 18:13:43 +02:00
co-authored by Claude Opus 5.5
parent befa1c2404
commit b1bdae6e59
9 changed files with 362 additions and 33 deletions
@@ -5,6 +5,7 @@ import { Link, useLocation, useNavigate, useParams, useSearchParams } from "reac
import { RichTextEditor } from "../../components/compose/RichTextEditor";
import { TypedPasswordInput } from "../../components/TypedPasswordInput";
import { ReadingPanePicker } from "../../components/mail/ReadingPanePicker";
import { useT } from "../../i18n";
import { api, ApiError } from "../../lib/api";
import type { CalendarOut, ReminderPref } from "../../lib/types";
@@ -748,6 +749,14 @@ function AppearanceSection() {
))}
</div>
</div>
<div className="space-y-2 border-b border-app-border py-3 text-sm">
<span className="text-app-muted">{t("display.readingPane")}</span>
<div className="max-w-md">
<ReadingPanePicker />
</div>
{/* Saved per device, like the theme: the right choice depends on the screen. */}
<p className="text-xs text-app-faint">{t("display.phoneNote")}</p>
</div>
<label className="flex items-center justify-between border-b border-app-border py-2 text-sm">
<span className="text-app-muted">{t("settings.threadOrder")}</span>
<select