Files
gotermix/internals/web/shell.html
T

252 lines
13 KiB
HTML

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>GoTermix</title>
<link rel="icon" type="image/svg+xml" href="/favicon.svg">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/xterm@5.3.0/css/xterm.css" />
<link rel="stylesheet" href="/static/app.css" />
<script src="https://cdn.jsdelivr.net/npm/xterm@5.3.0/lib/xterm.js"></script>
<script src="https://cdn.jsdelivr.net/npm/xterm-addon-fit@0.8.0/lib/xterm-addon-fit.js"></script>
</head>
<body>
<!-- ── Upload modal ───────────────────────────────────────────────── -->
<div class="m-overlay hidden" id="upOverlay" onclick="bgClose(event,'upOverlay')">
<div class="m-card">
<div class="m-head">
<span class="m-title">
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"/>
<polyline points="17 8 12 3 7 8"/><line x1="12" y1="3" x2="12" y2="15"/>
</svg>
Upload File
</span>
<button class="m-x" onclick="closeModal('upOverlay')">&#215;</button>
</div>
<div class="m-body">
<div class="file-zone" id="fileZone" onclick="document.getElementById('upFile').click()">
<div class="file-zone-icon">
<svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5">
<path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"/>
<polyline points="17 8 12 3 7 8"/><line x1="12" y1="3" x2="12" y2="15"/>
</svg>
</div>
<div class="file-zone-name" id="upFileName">Click to select file</div>
<input type="file" id="upFile" style="display:none" onchange="onFileChosen()">
</div>
<label class="m-label">Destination directory</label>
<input class="m-input" type="text" id="upDest" placeholder="leave empty for cwd, or /opt/myapp">
<button class="m-btn" id="upBtn" onclick="doUpload()">
<div class="spin"></div>
<span class="btn-text">Upload</span>
</button>
<div class="m-fb" id="upFb"></div>
</div>
</div>
</div>
<!-- ── Download modal ─────────────────────────────────────────────── -->
<div class="m-overlay hidden" id="dlOverlay" onclick="bgClose(event,'dlOverlay')">
<div class="m-card">
<div class="m-head">
<span class="m-title">
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"/>
<polyline points="7 10 12 15 17 10"/><line x1="12" y1="15" x2="12" y2="3"/>
</svg>
Download File
</span>
<button class="m-x" onclick="closeModal('dlOverlay')">&#215;</button>
</div>
<div class="m-body">
<label class="m-label">File path on server</label>
<input class="m-input" type="text" id="dlPath"
placeholder="/var/log/syslog"
onkeydown="if(event.key==='Enter') doDownload()">
<button class="m-btn ghost" onclick="doDownload()">
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"/>
<polyline points="7 10 12 15 17 10"/><line x1="12" y1="15" x2="12" y2="3"/>
</svg>
Download
</button>
<div class="m-fb" id="dlFb"></div>
</div>
</div>
</div>
<!-- ── Tab bar ────────────────────────────────────────────────────── -->
<div id="tabBar">
<div id="tabList">
<!-- tab items injected before this button -->
<button class="tab-new" id="tabNew" title="New tab (Alt+T)" onclick="newTab()">+</button>
</div>
</div>
<!-- ── Terminal container (panes injected by JS) ─────────────────── -->
<div id="termContainer"></div>
<!-- ── Compact toolbar ────────────────────────────────────────────── -->
<div class="toolbar">
<div class="tb-left">
<div class="dot" id="dot"></div>
<span class="status-label" id="statusLabel">connecting...</span>
</div>
<div class="tb-right">
<!-- Split left/right (Alt+H) -->
<button class="tb-btn" onclick="splitPane('h')" title="Split left/right (Alt+H)">
<svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<rect x="2" y="3" width="20" height="18" rx="2"/>
<line x1="12" y1="3" x2="12" y2="21"/>
</svg>
Split H
</button>
<!-- Split top/bottom (Alt+V) -->
<button class="tb-btn" onclick="splitPane('v')" title="Split top/bottom (Alt+V)">
<svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<rect x="2" y="3" width="20" height="18" rx="2"/>
<line x1="2" y1="12" x2="22" y2="12"/>
</svg>
Split V
</button>
<!-- Close active pane (Alt+X) -->
<button class="tb-btn" onclick="closePane()" title="Close active pane (Alt+X)">
<svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<rect x="2" y="3" width="20" height="18" rx="2"/>
<line x1="9" y1="9" x2="15" y2="15"/><line x1="15" y1="9" x2="9" y2="15"/>
</svg>
Pane X
</button>
<div class="tb-sep"></div>
<!-- Copy workspace link -->
<button class="tb-btn accent" id="copyBtn" onclick="copyLink()" title="Copy workspace link">
<svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<rect x="9" y="9" width="13" height="13" rx="2"/>
<path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"/>
</svg>
Link
</button>
<!-- Info / shortcuts -->
<button class="tb-btn tb-info" onclick="openModal('infoOverlay')" title="Keyboard shortcuts &amp; help">
<svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<circle cx="12" cy="12" r="10"/>
<line x1="12" y1="8" x2="12" y2="8" stroke-linecap="round" stroke-width="2.5"/>
<line x1="12" y1="12" x2="12" y2="16"/>
</svg>
Info
</button>
<!-- End Session -->
<button class="tb-btn tb-danger" onclick="endSession()" title="End session — clears saved layout, next open starts fresh">
<svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<path d="M9 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h4"/>
<polyline points="16 17 21 12 16 7"/>
<line x1="21" y1="12" x2="9" y2="12"/>
</svg>
End
</button>
<!-- Logout (sign out, workspace preserved) -->
<button class="tb-btn tb-logout" onclick="doLogout()" title="Sign out — workspace is preserved, sign in again to resume">
<svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<rect x="3" y="11" width="18" height="11" rx="2"/>
<path d="M7 11V7a5 5 0 0 1 10 0v4"/>
</svg>
Logout
</button>
<!-- Upload -->
<button class="tb-btn" onclick="openModal('upOverlay')" title="Upload file">
<svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"/>
<polyline points="17 8 12 3 7 8"/><line x1="12" y1="3" x2="12" y2="15"/>
</svg>
Upload
</button>
<!-- Download -->
<button class="tb-btn" onclick="openModal('dlOverlay')" title="Download file">
<svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"/>
<polyline points="7 10 12 15 17 10"/><line x1="12" y1="15" x2="12" y2="3"/>
</svg>
Down
</button>
</div>
</div>
<!-- ── Info modal ─────────────────────────────────────────────────── -->
<div class="m-overlay hidden" id="infoOverlay" onclick="bgClose(event,'infoOverlay')">
<div class="m-card" style="max-width:520px;">
<div class="m-head">
<span class="m-title">
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<circle cx="12" cy="12" r="10"/>
<line x1="12" y1="8" x2="12" y2="8"/><line x1="12" y1="12" x2="12" y2="16"/>
</svg>
GoTermix — Quick Reference
</span>
<button class="m-x" onclick="closeModal('infoOverlay')">&#215;</button>
</div>
<div class="m-body" style="padding:16px 20px 20px;">
<div class="info-section-label">Tabs</div>
<table class="info-table">
<tr><td><kbd>Alt+T</kbd></td><td>New tab</td></tr>
<tr><td><kbd>Alt+W</kbd></td><td>Close active tab</td></tr>
<tr><td><kbd>Alt+Shift+&larr;/&rarr;</kbd></td><td>Switch to previous / next tab</td></tr>
<tr><td>Right-click tab label</td><td>Rename tab</td></tr>
</table>
<div class="info-section-label">Split panes</div>
<table class="info-table">
<tr><td><kbd>Alt+H</kbd></td><td>Split active pane left / right</td></tr>
<tr><td><kbd>Alt+V</kbd></td><td>Split active pane top / bottom</td></tr>
<tr><td><kbd>Alt+X</kbd></td><td>Close active pane</td></tr>
<tr><td>Drag divider</td><td>Resize panes</td></tr>
<tr><td>Click pane</td><td>Focus pane</td></tr>
</table>
<div class="info-section-label">Copy &amp; paste</div>
<table class="info-table">
<tr><td><kbd>Ctrl+Shift+C</kbd></td><td>Copy selection</td></tr>
<tr><td><kbd>Ctrl+V</kbd></td><td>Paste from clipboard</td></tr>
<tr><td>Mouse drag</td><td>Select text</td></tr>
</table>
<div class="info-section-label">Word navigation (shell readline)</div>
<table class="info-table">
<tr><td><kbd>Ctrl+&larr;</kbd></td><td>Word backward</td></tr>
<tr><td><kbd>Ctrl+&rarr;</kbd></td><td>Word forward</td></tr>
</table>
<div class="info-section-label">Session &amp; files</div>
<table class="info-table">
<tr><td>Link button</td><td>Copy shareable workspace URL — open on any device to resume all tabs &amp; splits</td></tr>
<tr><td>End button</td><td>Clear saved layout; next visit starts fresh</td></tr>
<tr><td>Logout button</td><td>Sign out — workspace and all terminals are preserved; sign in again at the same URL to resume</td></tr>
<tr><td>Upload button</td><td>Upload file to server (lands in active shell's cwd by default)</td></tr>
<tr><td>Down button</td><td>Download file from server by path</td></tr>
</table>
<div class="info-section-label">Session timeout</div>
<table class="info-table">
<tr><td>Auto-logout</td><td>30 minutes of inactivity signs you out automatically (workspace preserved)</td></tr>
<tr><td>Active sessions</td><td>Session extends automatically while you are active</td></tr>
</table>
</div>
</div>
</div>
<!-- ── Toast ──────────────────────────────────────────────────────── -->
<div class="toast" id="toast"></div>
<script>
// Workspace context — injected server-side, consumed by app.js
const WORKSPACE_ID = "[[WORKSPACE_ID]]";
</script>
<script src="/static/app.js"></script>
</body>
</html>