feat: a small terminal or folder icon before each tab's name says what it holds
This commit is contained in:
1 parent
96163ebf86
commit
c003b51b4c
2 files changed
+20
-3
No files matched your search
@@ -333,7 +333,11 @@ body.multi .tabs, body.multi-hint .tabs { max-height:48px; opacity:1; padding-to
|
|||||||
.tab.on { background:var(--panel); color:var(--text); }
|
.tab.on { background:var(--panel); color:var(--text); }
|
||||||
.tab.enter, .tab.leave { max-width:0; opacity:0; padding:0; }
|
.tab.enter, .tab.leave { max-width:0; opacity:0; padding:0; }
|
||||||
.tab.dragging { opacity:.3; }
|
.tab.dragging { opacity:.3; }
|
||||||
.tab-title { flex:1; overflow:hidden; text-overflow:ellipsis; min-width:0; }
|
.tab-title { flex:1; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; min-width:0; }
|
||||||
|
/* What a tab holds, just before its name. */
|
||||||
|
.tab-kinds { display:inline-flex; gap:3px; flex:none; color:var(--muted); opacity:.75; }
|
||||||
|
.tab.on .tab-kinds { color:var(--text); opacity:.6; }
|
||||||
|
.tab-kinds svg { display:block; }
|
||||||
.tab-edit { width:auto; min-width:60px; max-width:150px; height:24px; padding:2px 6px; font-size:13px; }
|
.tab-edit { width:auto; min-width:60px; max-width:150px; height:24px; padding:2px 6px; font-size:13px; }
|
||||||
.tab-x, .pane-x { flex:none; width:20px; height:20px; padding:0; display:inline-flex; align-items:center; justify-content:center;
|
.tab-x, .pane-x { flex:none; width:20px; height:20px; padding:0; display:inline-flex; align-items:center; justify-content:center;
|
||||||
background:transparent; border:0; border-radius:5px; color:var(--muted); opacity:.6; transition:opacity .15s, background .15s, color .15s; }
|
background:transparent; border:0; border-radius:5px; color:var(--muted); opacity:.6; transition:opacity .15s, background .15s, color .15s; }
|
||||||
|
|||||||
@@ -22,6 +22,10 @@
|
|||||||
const tabs = [];
|
const tabs = [];
|
||||||
let active = null, activePane = null;
|
let active = null, activePane = null;
|
||||||
const tabOf = s => tabs.find(t => t.panes.includes(s));
|
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) {
|
function makeTab(panes, index) {
|
||||||
const t = { title: null, panes: panes, layout: panes.length === 1 ? '1' : 'h', c: 0.5, r: 0.5, gutters: [] };
|
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));
|
panes.forEach(s => t.view.appendChild(s.el));
|
||||||
t.el = document.createElement('div');
|
t.el = document.createElement('div');
|
||||||
t.el.className = 'tab enter';
|
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>';
|
'<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.addEventListener('click', ev => { if (!ev.target.closest('.tab-x, input') && !dragJustEnded) activate(t); });
|
||||||
t.el.querySelector('.tab-x').onclick = ev => { ev.stopPropagation(); closeTab(t); };
|
t.el.querySelector('.tab-x').onclick = ev => { ev.stopPropagation(); closeTab(t); };
|
||||||
@@ -64,7 +68,8 @@
|
|||||||
function fitTabs() {
|
function fitTabs() {
|
||||||
ruler.font = W.font + 'px ' + getComputedStyle(document.body).fontFamily;
|
ruler.font = W.font + 'px ' + getComputedStyle(document.body).fontFamily;
|
||||||
const live = tabs;
|
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 strip = $('tabs');
|
||||||
const room = strip.clientWidth - parseFloat(getComputedStyle(strip).paddingLeft) * 2 - addBtn.offsetWidth - 4 * (live.length + 1);
|
const room = strip.clientWidth - parseFloat(getComputedStyle(strip).paddingLeft) * 2 - addBtn.offsetWidth - 4 * (live.length + 1);
|
||||||
let cap = W.max;
|
let cap = W.max;
|
||||||
@@ -83,6 +88,14 @@
|
|||||||
|
|
||||||
function renderTab(t) {
|
function renderTab(t) {
|
||||||
t.el.querySelector('.tab-title').textContent = tabTitle(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);
|
const ssh = t.panes.some(s => s.ssh);
|
||||||
if (ssh !== !!t.el.querySelector('.badge-ssh')) {
|
if (ssh !== !!t.el.querySelector('.badge-ssh')) {
|
||||||
if (ssh) t.el.querySelector('.dot').insertAdjacentHTML('afterend', '<span class="badge-ssh">SSH</span>');
|
if (ssh) t.el.querySelector('.dot').insertAdjacentHTML('afterend', '<span class="badge-ssh">SSH</span>');
|
||||||
|
|||||||
Reference in new issue
Block a user