feat: a small terminal or folder icon before each tab's name says what it holds

This commit is contained in:
redtea committed 2026-10-16 10:12:00 +03:00
1 parent 96163ebf86
commit c003b51b4c
2 files changed
+20 -3

No files matched your search

+15 -2
View File
@@ -22,6 +22,10 @@
const tabs = [];
let active = null, activePane = null;
const tabOf = s => tabs.find(t => t.panes.includes(s));
const KIND_ICON = {
term: '<svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"><path d="m5 7 5 5-5 5M12 17h7"/></svg>',
files: '<svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M3 7a2 2 0 0 1 2-2h4l2 2.5h8a2 2 0 0 1 2 2V17a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z"/></svg>'
};
function makeTab(panes, index) {
const t = { title: null, panes: panes, layout: panes.length === 1 ? '1' : 'h', c: 0.5, r: 0.5, gutters: [] };
@@ -31,7 +35,7 @@
panes.forEach(s => t.view.appendChild(s.el));
t.el = document.createElement('div');
t.el.className = 'tab enter';
t.el.innerHTML = '<span class="dot wait"></span><span class="tab-title"></span>' +
t.el.innerHTML = '<span class="dot wait"></span><span class="tab-kinds"></span><span class="tab-title"></span>' +
'<button type="button" class="tab-x" title="Закрыть вкладку" aria-label="Закрыть вкладку">' + X + '</button>';
t.el.addEventListener('click', ev => { if (!ev.target.closest('.tab-x, input') && !dragJustEnded) activate(t); });
t.el.querySelector('.tab-x').onclick = ev => { ev.stopPropagation(); closeTab(t); };
@@ -64,7 +68,8 @@
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 + (t.panes.some(p => p.ssh) ? 46 : 0))));
const want = live.map(t => Math.min(W.max, Math.max(W.base, Math.ceil(ruler.measureText(tabTitle(t)).width) + CHROME + (t.panes.some(p => p.ssh) ? 46 : 0) +
18 * new Set(t.panes.map(p => /files$/.test(p.kind))).size)));
const strip = $('tabs');
const room = strip.clientWidth - parseFloat(getComputedStyle(strip).paddingLeft) * 2 - addBtn.offsetWidth - 4 * (live.length + 1);
let cap = W.max;
@@ -83,6 +88,14 @@
function renderTab(t) {
t.el.querySelector('.tab-title').textContent = tabTitle(t);
// Before the name, what the tab holds: a terminal, files, or both.
const kinds = [...new Set(t.panes.map(p => /files$/.test(p.kind) ? 'files' : 'term'))];
const k = t.el.querySelector('.tab-kinds');
if (k.dataset.k !== kinds.join()) {
k.dataset.k = kinds.join();
k.innerHTML = kinds.map(x => KIND_ICON[x]).join('');
k.title = kinds.map(x => x === 'files' ? 'файлы' : 'терминал').join(' и ');
}
const ssh = t.panes.some(s => s.ssh);
if (ssh !== !!t.el.querySelector('.badge-ssh')) {
if (ssh) t.el.querySelector('.dot').insertAdjacentHTML('afterend', '<span class="badge-ssh">SSH</span>');