feat: the password is turned off by hand in the account, with a passkey in place; password change; tabs sized by their titles

This commit is contained in:
redtea committed 2026-10-14 20:46:35 +03:00
1 parent 67222e2e05
commit 6dd1120a41
9 files changed
+212 -25

No files matched your search

+29 -1
View File
@@ -173,8 +173,9 @@
const at = index == null ? tabs.length : index;
tablist.insertBefore(t.el, tabs[at] ? tabs[at].el : mark);
tabs.splice(at, 0, t);
requestAnimationFrame(() => requestAnimationFrame(() => t.el.classList.remove('enter')));
renderTab(t);
fitTabs();
requestAnimationFrame(() => requestAnimationFrame(() => t.el.classList.remove('enter')));
return t;
}
function tabTitle(t) {
@@ -182,8 +183,35 @@
const a = t.panes[0].agent;
return t.panes.length > 1 ? a.name + ' +' + (t.panes.length - 1) : a.name;
}
// Tab widths: as wide as the title wants, from a comfortable minimum up to
// a maximum; when they do not fit, all give way evenly down to a floor,
// titles cut with "…", and below the floor the strip scrolls instead.
const ruler = document.createElement('canvas').getContext('2d');
const W = touch ? { min: 76, base: 108, max: 170, font: 12 } : { min: 96, base: 150, max: 280, font: 13 };
const CHROME = touch ? 52 : 62; // padding, dot, gaps, close button, borders
function fitTabs() {
ruler.font = W.font + 'px ' + getComputedStyle(document.body).fontFamily;
const live = tabs;
const want = live.map(t => Math.min(W.max, Math.max(W.base, Math.ceil(ruler.measureText(tabTitle(t)).width) + CHROME)));
const strip = $('tabs');
const room = strip.clientWidth - parseFloat(getComputedStyle(strip).paddingLeft) * 2 - addBtn.offsetWidth - 4 * (live.length + 1);
let cap = W.max;
if (want.reduce((a, b) => a + b, 0) > room) {
// The widest give way first, to one width for all at the most.
let lo = W.min, hi = W.max;
for (let k = 0; k < 20; k++) {
const mid = (lo + hi) / 2;
if (want.reduce((a, b) => a + Math.min(b, mid), 0) > room) hi = mid; else lo = mid;
}
cap = Math.max(W.min, Math.floor(lo));
}
live.forEach((t, i) => { t.el.style.width = Math.min(want[i], cap) + 'px'; });
}
window.addEventListener('resize', () => fitTabs());
function renderTab(t) {
t.el.querySelector('.tab-title').textContent = tabTitle(t);
requestAnimationFrame(fitTabs);
t.el.title = t.panes.map(s => s.agent.user + '@' + s.agent.host).join(', ');
// The tab's dot: red if any shell failed, amber while one connects.
const st = t.panes.map(s => s.state);