feat(terminal): styling improvements and shortcut

This commit is contained in:
2025-10-02 20:26:34 +02:00
parent 7cee2ff94f
commit 489fdafa1c
4 changed files with 108 additions and 11 deletions

View File

@@ -14,6 +14,14 @@
this.dockEl = null;
this.dockBtnEl = null;
this.lastNodeIp = null;
this.fallbackContainer = null;
try {
this._onKeydown = this._onKeydown.bind(this);
document.addEventListener('keydown', this._onKeydown);
} catch (_) {
// ignore if document not available
}
}
open(container, nodeIp) {
@@ -60,6 +68,8 @@
this._connect(nodeIp);
} else if (this.lastNodeIp && !this.socket) {
this._connect(this.lastNodeIp);
} else if (!this.socket && !this.lastNodeIp) {
this._updateTitle(null);
}
} catch (err) {
console.error('TerminalPanel.open error:', err);
@@ -136,8 +146,7 @@
_connect(nodeIp) {
try {
const titleEl = this.panelEl.querySelector('.terminal-title');
if (titleEl) titleEl.textContent = `Terminal — ${nodeIp}`;
this._updateTitle(nodeIp);
// Close previous socket if switching node
if (this.socket) {
@@ -254,6 +263,75 @@
if (this.dockEl) this.dockEl.classList.remove('visible');
}
_resolveContainer() {
if (this.container && document.body && document.body.contains(this.container)) {
return this.container;
}
const sharedDrawer = window.__sharedDrawerInstance;
if (sharedDrawer && sharedDrawer.terminalPanelContainer) {
return sharedDrawer.terminalPanelContainer;
}
if (this.fallbackContainer && document.body && document.body.contains(this.fallbackContainer)) {
return this.fallbackContainer;
}
if (typeof document !== 'undefined') {
const fallback = document.createElement('div');
fallback.className = 'terminal-panel-container';
document.body.appendChild(fallback);
this.fallbackContainer = fallback;
return fallback;
}
return null;
}
_onKeydown(event) {
try {
if (!event || event.defaultPrevented) return;
if (event.key !== 't' && event.key !== 'T') return;
if (event.repeat) return;
if (event.metaKey || event.ctrlKey || event.altKey) return;
const activeEl = document.activeElement;
if (activeEl) {
const tagName = activeEl.tagName;
const isEditable = activeEl.isContentEditable;
if (isEditable || tagName === 'INPUT' || tagName === 'TEXTAREA' || tagName === 'SELECT') {
return;
}
}
event.preventDefault();
this.toggleVisibility();
} catch (_) {
// swallow errors from key handler to avoid breaking global listeners
}
}
toggleVisibility() {
try {
if (this.isOpen && !this.isMinimized) {
this.minimize();
return;
}
if (this.isOpen && this.isMinimized) {
this.restore();
return;
}
const targetContainer = this._resolveContainer();
if (!targetContainer) return;
const targetIp = this.lastNodeIp || this.connectedIp || null;
this.open(targetContainer, targetIp);
} catch (err) {
console.error('TerminalPanel.toggleVisibility error:', err);
}
}
_send(text) {
try {
if (!this.socket || this.socket.readyState !== 1) {
@@ -267,6 +345,13 @@
}
}
_updateTitle(nodeIp) {
if (!this.panelEl) return;
const titleEl = this.panelEl.querySelector('.terminal-title');
if (!titleEl) return;
titleEl.textContent = nodeIp ? `Terminal — ${nodeIp}` : 'Terminal';
}
_clear() {
if (this.logEl) this.logEl.textContent = '';
}