feat: add status bar with connection indicator and cd path detection
This commit is contained in:
@@ -411,26 +411,32 @@
|
||||
for (let i = 0; i < totalTerminals; i++) {
|
||||
const pane = document.createElement('div');
|
||||
pane.className = 'terminal-pane';
|
||||
pane.style.overflow = 'hidden';
|
||||
pane.style.margin = '0';
|
||||
pane.style.padding = '0';
|
||||
pane.style.position = 'relative';
|
||||
|
||||
const statusDiv = document.createElement('div');
|
||||
statusDiv.className = 'pane-status';
|
||||
|
||||
const addressText = document.createElement('span');
|
||||
addressText.className = 'pane-address';
|
||||
addressText.textContent = shell;
|
||||
statusDiv.appendChild(addressText);
|
||||
|
||||
const statusIndicator = document.createElement('span');
|
||||
statusIndicator.className = 'status-indicator connecting';
|
||||
statusIndicator.title = 'Connecting...';
|
||||
statusDiv.appendChild(statusIndicator);
|
||||
pane.appendChild(statusDiv);
|
||||
|
||||
const contentDiv = document.createElement('div');
|
||||
contentDiv.className = 'terminal-content';
|
||||
pane.appendChild(contentDiv);
|
||||
|
||||
terminalsContainer.appendChild(pane);
|
||||
|
||||
try {
|
||||
const ws = new WebSocket(wsUrl);
|
||||
websockets.push(ws);
|
||||
statusIndicators.push(statusIndicator);
|
||||
const { term, fitAddon } = createTerminal(pane, ws, statusIndicator);
|
||||
const { term, fitAddon } = createTerminal(contentDiv, ws, statusIndicator, addressText);
|
||||
terminals.push(term);
|
||||
fitAddons.push(fitAddon);
|
||||
} catch (err) {
|
||||
@@ -462,7 +468,7 @@
|
||||
});
|
||||
}
|
||||
|
||||
function createTerminal(container, ws, statusIndicator) {
|
||||
function createTerminal(container, ws, statusIndicator, addressText) {
|
||||
const isDark = currentBrightness < 50;
|
||||
const bgValue = Math.round((currentBrightness / 100) * 255);
|
||||
const bgColor = `rgb(${bgValue}, ${bgValue}, ${bgValue})`;
|
||||
@@ -530,12 +536,14 @@
|
||||
};
|
||||
|
||||
ws.onmessage = (event) => {
|
||||
let text;
|
||||
if (event.data instanceof ArrayBuffer) {
|
||||
const text = new TextDecoder().decode(event.data);
|
||||
term.write(text);
|
||||
text = new TextDecoder().decode(event.data);
|
||||
} else {
|
||||
term.write(event.data);
|
||||
text = event.data;
|
||||
}
|
||||
|
||||
term.write(text);
|
||||
};
|
||||
|
||||
ws.onclose = () => {
|
||||
@@ -554,6 +562,13 @@
|
||||
};
|
||||
|
||||
term.onData((data) => {
|
||||
if (addressText) {
|
||||
const trimmed = data.trim();
|
||||
const cdMatch = trimmed.match(/^cd\s+(.+)/i);
|
||||
if (cdMatch && cdMatch[1]) {
|
||||
addressText.textContent = cdMatch[1].trim();
|
||||
}
|
||||
}
|
||||
if (ws && ws.readyState === WebSocket.OPEN) {
|
||||
ws.send(data);
|
||||
}
|
||||
|
||||
@@ -89,29 +89,20 @@ html, body {
|
||||
|
||||
.terminal-pane {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
background: var(--bg-primary);
|
||||
overflow: hidden;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.terminal-pane .xterm {
|
||||
height: 100%;
|
||||
margin: 0 !important;
|
||||
padding: 0 !important;
|
||||
}
|
||||
|
||||
.terminal-pane .xterm-viewport {
|
||||
margin: 0 !important;
|
||||
padding: 0 !important;
|
||||
}
|
||||
|
||||
.pane-status {
|
||||
position: absolute;
|
||||
top: 6px;
|
||||
right: 6px;
|
||||
z-index: 10;
|
||||
pointer-events: none;
|
||||
height: 20px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding-right: 12px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.status-indicator {
|
||||
@@ -120,6 +111,41 @@ html, body {
|
||||
border-radius: 50%;
|
||||
display: block;
|
||||
transition: background 0.3s, box-shadow 0.3s;
|
||||
margin-left: 8px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.pane-address {
|
||||
font-size: 11px;
|
||||
color: var(--text-secondary);
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.terminal-content {
|
||||
flex: 1;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.terminal-content .xterm {
|
||||
height: 100%;
|
||||
margin: 0 !important;
|
||||
padding: 0 !important;
|
||||
}
|
||||
|
||||
.terminal-content .xterm-viewport {
|
||||
margin: 0 !important;
|
||||
padding: 0 !important;
|
||||
}
|
||||
|
||||
.status-indicator {
|
||||
width: 6px;
|
||||
height: 6px;
|
||||
border-radius: 50%;
|
||||
display: block;
|
||||
transition: background 0.3s, box-shadow 0.3s;
|
||||
}
|
||||
|
||||
.status-indicator.connected {
|
||||
|
||||
Reference in New Issue
Block a user