diff --git a/public/mail.js b/public/mail.js
index e704150..8d5d332 100644
--- a/public/mail.js
+++ b/public/mail.js
@@ -38,7 +38,7 @@ const mailHasRemote = html => /
]+src=["']?https?:|url\(\s*["']?https?:/i.
// ---- unread badge and Home card
async function mailPoll() {
if (!(allowed('mail') && cfg.mail)) return;
- try { const s = await jfetch('/api/mail/status'); mail.st = s; mail.accts = s.accounts || mail.accts; const n = s.connected && s.unread ? s.unread : 0; if (n !== mailUnread) { mailUnread = n; renderNav(); } } catch {}
+ try { const s = await jfetch('/api/mail/status'); mail.st = s; mail.accts = s.accounts || mail.accts; const n = s.connected && s.unread ? s.unread : 0; if (n !== mailUnread) { mailUnread = n; renderNav(); } if (location.hash.startsWith('#/mail') && typeof mailDrawChips === 'function') mailDrawChips(); } catch {}
}
async function renderMailCard(el) {
if (!el) return;
@@ -180,12 +180,16 @@ async function viewMail(args = []) {
jfetch('/api/mail/folders?acct=' + encodeURIComponent(acct)).then(f => { if (mail.acct !== acct) return; mail.folders = f; mcPut('f:' + acct, { folders: f }); mailRefreshFolders(); }).catch(() => {});
mailPoll().then(() => { if (mail.st && location.hash.startsWith('#/mail')) mailRefreshFolders(); });
}
+/** One button per account with its own unread count, so you can see which one has new mail without switching. */
+const mailChips = () => `
${mail.accts.map(a => ``).join('')}
`;
+function mailBindChips() { document.querySelectorAll('.maccts button').forEach(b => b.onclick = () => { if (b.dataset.a === mail.acct) return; mail.q = ''; location.hash = '#/mail/f/' + encodeURIComponent(b.dataset.a + '~inbox'); }); }
+function mailDrawChips() { if (mail.accts.length < 2) return; document.querySelectorAll('.maccts').forEach(el => el.outerHTML = mailChips()); mailBindChips(); }
/** Redraw the folder pickers (names and unread counts) without touching the list or the open message. */
function mailRefreshFolders() {
+ mailDrawChips();
const fl = mail.folders; if (!fl.length) return;
const f = $('#mfsel'); if (f) f.innerHTML = fl.map(x => ``).join('');
- const side = document.querySelector('.mfold'); if (side) { const sel = side.querySelector('select'); side.innerHTML = (sel ? sel.outerHTML : '') + fl.map(x => `${esc(x.name)}${x.unread ? `${x.unread}` : ''}`).join(''); const s2 = side.querySelector('select'); if (s2) s2.onchange = e => { mail.q = ''; location.hash = '#/mail/f/' + encodeURIComponent(e.target.value + '~inbox'); }; }
- const acc = $('#macct'); if (acc && mail.accts.length) acc.innerHTML = mail.accts.map(a => ``).join('');
+ const side = document.querySelector('.mfold'); if (side) { const sel = side.querySelector('select'); side.innerHTML = (mail.accts.length > 1 ? mailChips() : '') + fl.map(x => `${esc(x.name)}${x.unread ? `${x.unread}` : ''}`).join(''); mailBindChips(); }
}
function mailConnectScreen(st) {
@@ -204,9 +208,9 @@ function mailConnectScreen(st) {
function mailShell(mode) {
const fl = mail.folders.length ? mail.folders : [{ id: 'inbox', name: 'Inbox', unread: mailUnread }];
$('#view').innerHTML = ``;
$('#mfsel').onchange = e => { mail.q = ''; location.hash = '#/mail/f/' + encodeURIComponent(e.target.value); };
- if ($('#macct2')) $('#macct2').onchange = e => { mail.q = ''; location.hash = '#/mail/f/' + encodeURIComponent(e.target.value + '~inbox'); };
- if ($('#macct')) $('#macct').onchange = e => { mail.q = ''; location.hash = '#/mail/f/' + encodeURIComponent(e.target.value + '~inbox'); };
+ mailBindChips();
$('#mnew').onclick = () => mailCompose();
$('#mrf').onclick = () => { mailLoadList(true); jfetch('/api/mail/folders?acct=' + encodeURIComponent(mail.acct)).then(f => { mail.folders = f; mailPoll(); }).catch(() => {}); };
let t; $('#mq').oninput = e => { clearTimeout(t); t = setTimeout(() => { mail.q = e.target.value.trim(); mailLoadList(true); }, 400); };
diff --git a/public/style.css b/public/style.css
index ce2e8ff..bffffe8 100644
--- a/public/style.css
+++ b/public/style.css
@@ -808,3 +808,14 @@ kbd { display: inline-block; padding: 1px 7px; border: 1px solid var(--line); bo
.vsl { position: absolute; top: 28%; z-index: 4; width: 38px; height: 38px; min-height: 0; padding: 0; border-radius: 50%; border: 1px solid var(--line); background: color-mix(in srgb, var(--panel) 92%, transparent); color: var(--text); font-size: 24px; line-height: 1; display: grid; place-items: center; cursor: pointer; box-shadow: 0 4px 14px rgba(0, 0, 0, .3); backdrop-filter: blur(6px); -webkit-backdrop-filter: blur(6px); }
.vsl[hidden] { display: none; } .vsl.l { left: -6px; } .vsl.r { right: -6px; }
@media (hover: none) { .vsl { display: none; } }
+/* Mail: one button per account, each with its own unread count */
+.maccts { display: flex; gap: 6px; overflow-x: auto; scrollbar-width: none; margin-bottom: 6px; padding-bottom: 2px; }
+.maccts::-webkit-scrollbar { display: none; }
+.maccts button { flex: none; display: flex; align-items: center; gap: 8px; max-width: 220px; min-height: 40px; padding: 4px 12px; border-radius: 12px; border: 1px solid var(--line); background: var(--panel); color: var(--muted); text-align: left; cursor: pointer; }
+.maccts button.on { background: var(--accent); color: var(--accent-t); border-color: transparent; }
+.maccts button.new:not(.on) { color: var(--text); border-color: var(--accent); }
+.maccts .mal { font-weight: 650; font-size: 14px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
+.maccts small { display: none; }
+.maccts .nbadge { margin-left: 2px; }
+.mfold .maccts { flex-direction: column; overflow: visible; margin-bottom: 10px; } .mfold .maccts button { max-width: none; } .mfold .maccts small { display: block; opacity: .75; font-size: 11px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
+.mfold .maccts .mal, .mfold .maccts small { display: block; } .mfold .maccts button > .mal { max-width: 100%; }
diff --git a/public/sw.js b/public/sw.js
index 1af1d22..7edc1dc 100644
--- a/public/sw.js
+++ b/public/sw.js
@@ -1,5 +1,5 @@
// App-shell cache only; Seafile/API traffic always goes to the network.
-const CACHE = 'hub-v27';
+const CACHE = 'hub-v28';
const SHARE = 'hub-share'; // files shared into the app from other apps, held until the person picks a folder
const SHELL = ['/icon.svg', '/manifest.webmanifest', '/icons/icon-192.png', '/icons/apple-touch-icon.png'];