diff --git a/public/mail.js b/public/mail.js
index 2aa0373..692656a 100644
--- a/public/mail.js
+++ b/public/mail.js
@@ -138,6 +138,15 @@ async function mailAdminCard() {
async function viewMail(args = []) {
const v = $('#view');
if (!cfg.mail) { v.innerHTML = '
Mail
Mail is not available to you.
'; return; }
+ // Moving between messages (or back to the list) in the same folder changes only the reader and the highlighted row: the page is not rebuilt,
+ // so there is no flash, and the list keeps its place.
+ const shell = document.querySelector('.mailapp'), k0 = args[0], key0 = args[1];
+ if (shell && v.contains(shell) && mail.st && mail.st.connected && mail.accts.length && (k0 === 'm' || k0 === undefined) && (k0 !== 'm' || !String(key0).includes('~') || String(key0).split('~')[0] === mail.acct)) {
+ const view = $('#view');
+ if (k0 === 'm') { if (shell.dataset.mode !== 'read') mail.listScroll = view.scrollTop; shell.dataset.mode = 'read'; mailMarkSel(key0); mailOpen(key0); }
+ else { shell.dataset.mode = 'list'; mail.msg = null; mailDrawReader(); mailMarkSel(''); requestAnimationFrame(() => { if (mail.listScroll) view.scrollTop = mail.listScroll; }); }
+ return;
+ }
// The accounts come from the server without any network call to the mail providers ("light"), so the page can draw at once; the folders, the message
// list and the real unread counts then load side by side instead of one after another.
let st = mail.st;
@@ -228,6 +237,7 @@ async function mailLoadList(reset) {
mailDrawList();
} catch (e) { if (showing) return; const el = $('#mrows'); if (el) el.innerHTML = `${esc(e.message)}
`; if (/Connect again/.test(e.message)) { mail.st = null; mcClear(); setTimeout(route, 1200); } }
}
+function mailMarkSel(id) { document.querySelectorAll('a.mrow').forEach(a => a.classList.toggle('sel', !!id && decodeURIComponent(a.getAttribute('href').slice(9)) === id)); }
function mailDrawList() {
const rows = $('#mrows'); if (!rows) return;
const sel = (location.hash.match(/^#\/mail\/m\/([^/]+)/) || [])[1];