style: modern dark UI refresh

- design-token palette (:root vars): deeper #0e0f13 base, indigo #7c8cff accent,
  layered surfaces, softer borders, shadow + radius scale
- tabs as floating rounded chips (active = elevated surface); refined dots
- key bar as rounded chips with gaps; Esc gets the accent tint
- toolbar icon buttons with rounded hover
- overlays (history/dashboard/qr/search/settings) get backdrop-blur + card +
  shadow; indigo primary buttons; consistent inputs with accent focus ring
- chrome uses a system UI font (terminal stays monospace)
- xterm dark theme + meta theme-color + manifest + app icon synced to the
  palette (indigo-gradient icon, accent cursor)
216 tests green; tsc + build clean.
This commit is contained in:
Yaojia Wang
2026-06-18 09:08:02 +02:00
parent e1a9439cce
commit 524f2073a0
6 changed files with 434 additions and 385 deletions

View File

@@ -1,6 +1,16 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" width="512" height="512"> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" width="512" height="512">
<rect width="512" height="512" rx="96" fill="#1a1a1a"/> <defs>
<g fill="none" stroke="#3fb950" stroke-width="34" stroke-linecap="round" stroke-linejoin="round"> <linearGradient id="bg" x1="0" y1="0" x2="1" y2="1">
<stop offset="0" stop-color="#1a1c26"/>
<stop offset="1" stop-color="#0e0f13"/>
</linearGradient>
<linearGradient id="fg" x1="0" y1="0" x2="1" y2="1">
<stop offset="0" stop-color="#9d7cff"/>
<stop offset="1" stop-color="#7c8cff"/>
</linearGradient>
</defs>
<rect width="512" height="512" rx="112" fill="url(#bg)"/>
<g fill="none" stroke="url(#fg)" stroke-width="36" stroke-linecap="round" stroke-linejoin="round">
<polyline points="150,196 226,256 150,316"/> <polyline points="150,196 226,256 150,316"/>
<line x1="268" y1="320" x2="372" y2="320"/> <line x1="268" y1="320" x2="372" y2="320"/>
</g> </g>

Before

Width:  |  Height:  |  Size: 357 B

After

Width:  |  Height:  |  Size: 721 B

View File

@@ -5,7 +5,7 @@
<meta name="viewport" content="width=device-width, initial-scale=1.0, viewport-fit=cover"> <meta name="viewport" content="width=device-width, initial-scale=1.0, viewport-fit=cover">
<title>Web Terminal</title> <title>Web Terminal</title>
<link rel="manifest" href="./manifest.webmanifest"> <link rel="manifest" href="./manifest.webmanifest">
<meta name="theme-color" content="#1a1a1a"> <meta name="theme-color" content="#0e0f13">
<link rel="apple-touch-icon" href="./icon.svg"> <link rel="apple-touch-icon" href="./icon.svg">
<meta name="apple-mobile-web-app-capable" content="yes"> <meta name="apple-mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="black"> <meta name="apple-mobile-web-app-status-bar-style" content="black">

View File

@@ -6,8 +6,8 @@
"scope": "./", "scope": "./",
"display": "standalone", "display": "standalone",
"orientation": "any", "orientation": "any",
"background_color": "#1a1a1a", "background_color": "#0e0f13",
"theme_color": "#1a1a1a", "theme_color": "#0e0f13",
"icons": [ "icons": [
{ {
"src": "./icon.svg", "src": "./icon.svg",

View File

@@ -13,14 +13,19 @@ export interface Settings {
} }
export const THEMES: Record<string, ITheme> = { export const THEMES: Record<string, ITheme> = {
dark: { background: '#1a1a1a', foreground: '#e8e8e8', cursor: '#e8e8e8' }, dark: {
light: { background: '#0e0f13',
background: '#f5f5f5', foreground: '#e7e8ec',
foreground: '#1a1a1a', cursor: '#7c8cff',
cursor: '#1a1a1a', selectionBackground: 'rgba(124,140,255,0.28)',
selectionBackground: '#bcd3f5',
}, },
solarized: { background: '#002b36', foreground: '#93a1a1', cursor: '#93a1a1' }, light: {
background: '#f6f7f9',
foreground: '#1a1d24',
cursor: '#5b6cff',
selectionBackground: '#cdd6ff',
},
solarized: { background: '#002b36', foreground: '#93a1a1', cursor: '#268bd2' },
} }
const KEY = 'web-terminal:settings' const KEY = 'web-terminal:settings'

View File

@@ -1,113 +1,357 @@
/* Web Terminal Styling */ /* Web Terminal — modern dark UI */
:root { :root {
/* Key bar is shown on ALL devices (clickable shortcut buttons). Touch /* palette (design tokens) */
devices get a taller bar with bigger tap targets. */ --bg: #0e0f13; /* terminal / deepest surface */
--tabbar-h: 36px; --surface-1: #15161c; /* tab bar, key bar */
--keybar-h: 42px; --surface-2: #1c1e26; /* tabs, buttons, cards */
--surface-3: #252834; /* hover / active */
--border: rgba(255, 255, 255, 0.07);
--border-strong: rgba(255, 255, 255, 0.13);
--text: #e7e8ec;
--text-dim: #9aa0ad;
--text-faint: #6b7080;
--accent: #7c8cff; /* indigo */
--accent-2: #9d7cff;
--accent-soft: rgba(124, 140, 255, 0.16);
--green: #46d07f;
--amber: #f5b14c;
--red: #ff6b6b;
--shadow: 0 10px 40px rgba(0, 0, 0, 0.55);
--radius: 9px;
--radius-lg: 14px;
--tabbar-h: 40px;
--keybar-h: 46px;
--ui-font: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif;
} }
/* Touch devices: bigger tap targets for tabs and the key bar. */
@media (pointer: coarse) { @media (pointer: coarse) {
:root { :root {
--tabbar-h: 44px; --tabbar-h: 48px;
--keybar-h: 58px; --keybar-h: 60px;
} }
} }
html, body { html,
body {
margin: 0; margin: 0;
padding: 0; padding: 0;
width: 100%; width: 100%;
height: 100%; height: 100%;
background-color: #1a1a1a; background-color: var(--bg);
font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', monospace; color: var(--text);
font-family: var(--ui-font);
overflow: hidden; overflow: hidden;
} }
/* ── Tab bar (top) ───────────────────────────────────────────────── */ * {
scrollbar-width: thin;
scrollbar-color: var(--surface-3) transparent;
}
/* ── Tab bar ─────────────────────────────────────────────────────── */
#tabbar { #tabbar {
position: fixed; position: fixed;
top: 0; inset: 0 0 auto 0;
left: 0;
right: 0;
height: var(--tabbar-h); height: var(--tabbar-h);
background-color: #222; background: linear-gradient(180deg, #181a22, var(--surface-1));
border-bottom: 1px solid #3a3a3a; border-bottom: 1px solid var(--border);
display: flex; display: flex;
align-items: stretch; align-items: stretch;
z-index: 1001; z-index: 1001;
} }
/* tabs: scrollable; toolbar: fixed cluster on the right */
#tabs { #tabs {
flex: 1 1 auto; flex: 1 1 auto;
display: flex; display: flex;
align-items: stretch; align-items: center;
gap: 2px;
padding: 0 4px;
overflow-x: auto; overflow-x: auto;
overflow-y: hidden; overflow-y: hidden;
scrollbar-width: thin; }
#tabs::-webkit-scrollbar {
height: 0;
} }
/* tabs as floating rounded chips */
.tab {
display: flex;
align-items: center;
gap: 2px;
height: calc(var(--tabbar-h) - 12px);
padding: 0 4px 0 10px;
border-radius: 8px;
color: var(--text-dim);
background: transparent;
cursor: pointer;
white-space: nowrap;
font-size: 13px;
user-select: none;
max-width: 220px;
transition:
background 0.12s ease,
color 0.12s ease;
}
.tab:hover {
background: var(--surface-2);
color: var(--text);
}
.tab.active {
background: var(--surface-3);
color: #fff;
box-shadow: inset 0 0 0 1px var(--border-strong);
}
.tab-dot {
width: 7px;
height: 7px;
border-radius: 50%;
margin-right: 8px;
flex: none;
background: var(--text-faint);
}
.dot-connected {
background: var(--green);
box-shadow: 0 0 6px rgba(70, 208, 127, 0.5);
}
.dot-connecting,
.dot-reconnecting {
background: var(--amber);
}
.dot-exited {
background: var(--red);
}
.tab-label {
padding-right: 4px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.tab-rename {
width: 120px;
margin: 0 4px;
padding: 3px 6px;
font: inherit;
font-size: 13px;
color: #fff;
background: var(--bg);
border: 1px solid var(--accent);
border-radius: 6px;
outline: none;
}
/* unread / Claude-waiting accents */
.tab.unread .tab-dot {
box-shadow: 0 0 0 3px var(--accent-soft);
}
.tab.unread .tab-label {
color: #fff;
font-weight: 600;
}
.tab-claude {
margin-right: 4px;
font-size: 12px;
flex: none;
}
.tab.claude-waiting {
background: rgba(245, 177, 76, 0.14);
box-shadow: inset 0 0 0 1px rgba(245, 177, 76, 0.5);
}
.tab.dragging {
opacity: 0.4;
}
.tab.drag-over {
box-shadow: inset 3px 0 0 var(--accent);
}
.tab-close {
background: none;
border: none;
color: var(--text-faint);
cursor: pointer;
font-size: 16px;
line-height: 1;
padding: 3px 6px;
border-radius: 6px;
flex: none;
}
.tab-close:hover {
background: rgba(255, 255, 255, 0.1);
color: #fff;
}
@media (pointer: fine) {
.tab:not(.active):not(:hover) .tab-close {
opacity: 0;
}
}
.tab-add {
background: none;
border: none;
color: var(--text-dim);
cursor: pointer;
font-size: 18px;
padding: 0 10px;
flex: none;
border-radius: 7px;
}
.tab-add:hover {
color: #fff;
background: var(--surface-2);
}
/* toolbar */
#toolbar { #toolbar {
flex: 0 0 auto; flex: 0 0 auto;
display: flex; display: flex;
align-items: center; align-items: center;
border-left: 1px solid #3a3a3a; gap: 2px;
padding: 0 6px;
border-left: 1px solid var(--border);
} }
.toolbtn { .toolbtn {
background: none; background: none;
border: none; border: none;
color: #aaa; color: var(--text-dim);
cursor: pointer; cursor: pointer;
font-size: 15px; font-size: 15px;
padding: 0 12px; padding: 7px 9px;
height: 100%; border-radius: 8px;
line-height: 1;
transition: background 0.12s ease;
} }
.toolbtn:hover { .toolbtn:hover {
color: #fff; color: #fff;
background-color: #2a2a2a; background: var(--surface-2);
}
/* ── Terminal area ───────────────────────────────────────────────── */
#term {
position: absolute;
inset: var(--tabbar-h) 0 var(--keybar-h) 0;
background: var(--bg);
overflow: hidden;
}
.term-pane {
position: absolute;
inset: 0;
padding: 6px 8px 0;
box-sizing: border-box;
overflow: hidden;
}
/* ── Key bar (rounded chips) ─────────────────────────────────────── */
#keybar {
position: fixed;
inset: auto 0 0 0;
height: var(--keybar-h);
background: var(--surface-1);
border-top: 1px solid var(--border);
display: flex;
align-items: center;
gap: 5px;
padding: 0 6px;
overflow-x: auto;
overflow-y: hidden;
z-index: 1000;
}
#keybar::-webkit-scrollbar {
height: 0;
}
#keybar button {
flex: 1 0 auto;
min-width: 46px;
height: calc(var(--keybar-h) - 14px);
padding: 0 12px;
border: 1px solid var(--border);
background: var(--surface-2);
color: var(--text);
font-family: var(--ui-font);
font-size: 13px;
cursor: pointer;
border-radius: 8px;
transition:
background 0.1s ease,
transform 0.05s ease;
user-select: none;
-webkit-user-select: none;
-webkit-touch-callout: none;
}
#keybar button:hover {
background: var(--surface-3);
}
#keybar button:active {
transform: translateY(1px);
background: var(--surface-3);
}
#keybar button.keybar-btn-primary {
background: var(--accent-soft);
color: #cdd4ff;
border-color: rgba(124, 140, 255, 0.4);
font-weight: 600;
min-width: 54px;
}
#keybar button.keybar-btn-primary:hover {
background: rgba(124, 140, 255, 0.26);
}
/* ── Shared: overlays, cards, inputs, buttons ────────────────────── */
.overlay {
position: fixed;
inset: 0;
z-index: 1200;
display: flex;
background: rgba(8, 9, 12, 0.6);
-webkit-backdrop-filter: blur(6px);
backdrop-filter: blur(6px);
} }
/* Search box overlay (M1) */
#searchbox { #searchbox {
position: fixed; position: fixed;
top: calc(var(--tabbar-h) + 6px); top: calc(var(--tabbar-h) + 8px);
right: 8px; right: 10px;
z-index: 1100; z-index: 1100;
display: flex; display: flex;
gap: 4px; gap: 5px;
padding: 6px; padding: 7px;
background-color: #2a2a2a; background: var(--surface-2);
border: 1px solid #3a3a3a; border: 1px solid var(--border-strong);
border-radius: 6px; border-radius: 10px;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.4); box-shadow: var(--shadow);
} }
.search-input { .search-input {
width: 180px; width: 190px;
padding: 4px 6px; padding: 5px 8px;
font: inherit; font: inherit;
font-size: 13px; font-size: 13px;
color: #fff; color: #fff;
background: #111; background: var(--bg);
border: 1px solid #444; border: 1px solid var(--border);
border-radius: 3px; border-radius: 7px;
outline: none; outline: none;
} }
.search-input:focus {
border-color: var(--accent);
}
#searchbox button { #searchbox button {
background: #333; background: var(--surface-3);
border: 1px solid #444; border: 1px solid var(--border);
color: #ddd; color: var(--text);
cursor: pointer; cursor: pointer;
border-radius: 3px; border-radius: 7px;
padding: 0 8px; padding: 0 10px;
} }
#searchbox button:hover { #searchbox button:hover {
background: #555; background: var(--accent-soft);
} }
/* QR connect modal (M5) */ /* QR modal */
#qrmodal { #qrmodal {
position: fixed; position: fixed;
inset: 0; inset: 0;
@@ -115,145 +359,106 @@ html, body {
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
background: rgba(0, 0, 0, 0.6); background: rgba(8, 9, 12, 0.6);
-webkit-backdrop-filter: blur(6px);
backdrop-filter: blur(6px);
} }
.qr-card { .qr-card {
background: #fff; background: var(--surface-2);
color: #111; color: var(--text);
border-radius: 12px; border: 1px solid var(--border-strong);
padding: 20px; border-radius: var(--radius-lg);
padding: 22px;
text-align: center; text-align: center;
max-width: 90vw; max-width: 90vw;
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.5); box-shadow: var(--shadow);
}
.qr-card canvas {
border-radius: 10px;
background: #fff;
padding: 8px;
} }
.qr-title { .qr-title {
font-weight: 600; font-weight: 600;
margin-bottom: 12px; margin-bottom: 14px;
} }
.qr-url { .qr-url {
margin-top: 10px; margin-top: 12px;
font-size: 13px; font-size: 13px;
color: #333; color: var(--accent);
word-break: break-all; word-break: break-all;
} }
.qr-note { .qr-note {
margin-top: 8px; margin-top: 8px;
font-size: 12px; font-size: 12px;
color: #666; color: var(--text-dim);
max-width: 240px; max-width: 240px;
} }
.qr-close { .qr-close {
margin-top: 14px; margin-top: 16px;
padding: 6px 18px; padding: 8px 20px;
border: none; border: 1px solid var(--border-strong);
border-radius: 6px; border-radius: 8px;
background: #1a1a1a; background: var(--surface-3);
color: #fff; color: #fff;
cursor: pointer; cursor: pointer;
font: inherit; font: inherit;
} }
.qr-close:hover {
background: var(--accent-soft);
}
/* Settings panel (M3) */ /* Settings panel */
#settingspanel { #settingspanel {
position: fixed; position: fixed;
top: calc(var(--tabbar-h) + 6px); top: calc(var(--tabbar-h) + 8px);
right: 8px; right: 10px;
z-index: 1100; z-index: 1100;
background: #2a2a2a; background: var(--surface-2);
border: 1px solid #3a3a3a; border: 1px solid var(--border-strong);
border-radius: 6px; border-radius: 12px;
padding: 10px; padding: 12px;
min-width: 210px; min-width: 220px;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.4); box-shadow: var(--shadow);
color: #ddd; color: var(--text);
} }
.settings-row { .settings-row {
display: flex; display: flex;
align-items: center; align-items: center;
gap: 6px; gap: 6px;
margin: 6px 0; margin: 8px 0;
} }
.settings-label { .settings-label {
width: 48px; width: 48px;
color: #aaa; color: var(--text-dim);
font-size: 13px; font-size: 13px;
} }
.settings-opt { .settings-opt {
background: #333; background: var(--surface-3);
border: 1px solid #444; border: 1px solid var(--border);
color: #ddd; color: var(--text);
border-radius: 4px; border-radius: 7px;
padding: 4px 9px; padding: 5px 10px;
cursor: pointer; cursor: pointer;
font: inherit; font: inherit;
font-size: 12px; font-size: 12px;
transition: background 0.1s ease;
}
.settings-opt:hover {
background: var(--surface-1);
} }
.settings-opt.active { .settings-opt.active {
background: #4a9eff; background: var(--accent);
color: #fff; color: #fff;
border-color: #4a9eff; border-color: var(--accent);
} }
.settings-size { .settings-size {
min-width: 22px; min-width: 22px;
text-align: center; text-align: center;
} }
/* Dashboard (M7) */ /* Dashboard + history share the centered-card look */
#dashboard { #dashboard,
position: fixed;
inset: 0;
z-index: 1200;
display: flex;
align-items: flex-start;
justify-content: center;
padding-top: 56px;
background: rgba(0, 0, 0, 0.6);
}
.dash-card {
background: #222;
border: 1px solid #3a3a3a;
border-radius: 10px;
min-width: 320px;
max-width: 90vw;
max-height: 70vh;
overflow-y: auto;
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.5);
}
.dash-title {
padding: 12px 16px;
font-weight: 600;
color: #fff;
border-bottom: 1px solid #3a3a3a;
}
.dash-row {
display: flex;
align-items: center;
gap: 10px;
padding: 10px 16px;
cursor: pointer;
color: #ddd;
border-bottom: 1px solid #2a2a2a;
}
.dash-row:hover {
background: #2a2a2a;
}
.dash-row.active {
background: #1a1a1a;
box-shadow: inset 3px 0 0 #4a9eff;
}
.dash-name {
flex: 1;
}
.dash-claude {
color: #aaa;
font-size: 13px;
}
.dash-claude.pending {
color: #ffcf8f;
font-weight: 600;
}
/* History / resume modal (O2) */
#historymodal { #historymodal {
position: fixed; position: fixed;
inset: 0; inset: 0;
@@ -261,35 +466,65 @@ html, body {
display: flex; display: flex;
align-items: flex-start; align-items: flex-start;
justify-content: center; justify-content: center;
padding-top: 56px; padding-top: 60px;
background: rgba(0, 0, 0, 0.6); background: rgba(8, 9, 12, 0.6);
-webkit-backdrop-filter: blur(6px);
backdrop-filter: blur(6px);
} }
.dash-card,
.hist-card { .hist-card {
background: #222; background: var(--surface-2);
border: 1px solid #3a3a3a; border: 1px solid var(--border-strong);
border-radius: 10px; border-radius: var(--radius-lg);
min-width: 360px; min-width: 340px;
max-width: 92vw; max-width: 92vw;
max-height: 72vh; max-height: 72vh;
overflow-y: auto; overflow-y: auto;
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.5); box-shadow: var(--shadow);
} }
.dash-title,
.hist-title { .hist-title {
padding: 12px 16px; padding: 14px 18px;
font-weight: 600; font-weight: 600;
color: #fff; color: #fff;
border-bottom: 1px solid #3a3a3a; border-bottom: 1px solid var(--border);
}
.hist-empty {
padding: 16px;
color: #aaa;
} }
.dash-row,
.hist-row { .hist-row {
display: flex; display: flex;
align-items: center; align-items: center;
gap: 10px; gap: 10px;
padding: 10px 16px; padding: 11px 18px;
border-bottom: 1px solid #2a2a2a; cursor: pointer;
color: var(--text);
border-bottom: 1px solid var(--border);
transition: background 0.1s ease;
}
.dash-row:hover,
.hist-row:hover {
background: var(--surface-3);
}
.dash-row.active {
box-shadow: inset 3px 0 0 var(--accent);
}
.dash-name {
flex: 1;
}
.dash-claude {
color: var(--text-dim);
font-size: 13px;
}
.dash-claude.pending {
color: var(--amber);
font-weight: 600;
}
.hist-empty {
padding: 18px;
color: var(--text-dim);
}
.hist-row {
cursor: default;
} }
.hist-main { .hist-main {
flex: 1 1 auto; flex: 1 1 auto;
@@ -300,7 +535,7 @@ html, body {
font-size: 13px; font-size: 13px;
} }
.hist-prev { .hist-prev {
color: #aaa; color: var(--text-dim);
font-size: 12px; font-size: 12px;
overflow: hidden; overflow: hidden;
text-overflow: ellipsis; text-overflow: ellipsis;
@@ -308,93 +543,32 @@ html, body {
} }
.hist-resume { .hist-resume {
flex: none; flex: none;
background: #2ea043; background: var(--accent);
color: #fff; color: #fff;
border: none; border: none;
border-radius: 5px; border-radius: 8px;
padding: 6px 14px; padding: 7px 15px;
cursor: pointer; cursor: pointer;
font: inherit; font: inherit;
font-weight: 500;
transition: background 0.1s ease;
} }
.hist-resume:hover { .hist-resume:hover {
background: #3fb950; background: var(--accent-2);
} }
.tab { /* Approval banner (H3) */
display: flex;
align-items: center;
padding: 0 4px 0 12px;
color: #aaa;
background-color: #2a2a2a;
border-right: 1px solid #1a1a1a;
cursor: pointer;
white-space: nowrap;
font-size: 13px;
user-select: none;
max-width: 200px;
}
.tab.active {
background-color: #1a1a1a;
color: #fff;
box-shadow: inset 0 -2px 0 #4a9eff; /* active underline accent */
}
/* Status dot — color reflects connection state. */
.tab-dot {
width: 8px;
height: 8px;
border-radius: 50%;
margin-right: 8px;
flex: none;
background-color: #666;
}
.dot-connected {
background-color: #3fb950; /* green */
}
.dot-connecting,
.dot-reconnecting {
background-color: #d29922; /* amber */
}
.dot-exited {
background-color: #f85149; /* red */
}
/* Unread: an inactive tab got new output — blue ring + brighter label. */
.tab.unread .tab-dot {
box-shadow: 0 0 0 2px rgba(74, 158, 255, 0.6);
}
.tab.unread .tab-label {
color: #fff;
font-weight: 600;
}
/* Claude Code activity glyph (H2/H4) */
.tab-claude {
margin-right: 6px;
font-size: 12px;
flex: none;
}
/* A background tab that needs approval gets an amber outline. */
.tab.claude-waiting {
background-color: #3a2a10;
box-shadow: inset 0 -2px 0 #d29922;
}
/* Approve/reject banner (H3) — sits just above the key bar. */
#approvalbar { #approvalbar {
position: fixed; position: fixed;
left: 0; inset: auto 0 var(--keybar-h) 0;
right: 0;
bottom: var(--keybar-h);
z-index: 1050; z-index: 1050;
display: flex; display: flex;
align-items: center; align-items: center;
gap: 10px; gap: 10px;
padding: 8px 12px; padding: 10px 14px;
background: #3a2a10; background: linear-gradient(180deg, rgba(245, 177, 76, 0.16), rgba(245, 177, 76, 0.08));
border-top: 1px solid #d29922; border-top: 1px solid rgba(245, 177, 76, 0.5);
color: #ffcf8f; color: #ffe0ad;
font-size: 14px; font-size: 14px;
} }
.approval-label { .approval-label {
@@ -403,157 +577,17 @@ html, body {
#approvalbar button { #approvalbar button {
flex: none; flex: none;
border: none; border: none;
border-radius: 5px; border-radius: 8px;
padding: 7px 16px; padding: 8px 16px;
cursor: pointer; cursor: pointer;
font: inherit; font: inherit;
font-weight: 600; font-weight: 600;
} }
.approval-yes { .approval-yes {
background: #2ea043; background: var(--green);
color: #fff; color: #06210f;
} }
.approval-no { .approval-no {
background: #c93c37; background: var(--red);
color: #fff; color: #2a0808;
}
/* Drag-to-reorder feedback. */
.tab.dragging {
opacity: 0.4;
}
.tab.drag-over {
box-shadow: inset 3px 0 0 #4a9eff; /* drop-position indicator */
}
.tab-label {
padding-right: 8px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
/* Inline rename input (double-click a tab) */
.tab-rename {
width: 110px;
margin: 0 4px;
padding: 2px 4px;
font: inherit;
font-size: 13px;
color: #fff;
background: #111;
border: 1px solid #4a9eff;
border-radius: 3px;
outline: none;
}
.tab-close {
background: none;
border: none;
color: #888;
cursor: pointer;
font-size: 15px;
line-height: 1;
padding: 2px 6px;
border-radius: 3px;
flex: none;
}
.tab-close:hover {
background-color: #444;
color: #fff;
}
/* Desktop (mouse): reveal × on hover/active to reduce clutter.
Touch devices keep × always visible (no hover). */
@media (pointer: fine) {
.tab:not(.active):not(:hover) .tab-close {
opacity: 0;
}
}
.tab-add {
background: none;
border: none;
color: #aaa;
cursor: pointer;
font-size: 18px;
padding: 0 14px;
user-select: none;
flex: none;
}
.tab-add:hover {
color: #fff;
}
/* ── Terminal area (holds one .term-pane per tab) ────────────────── */
#term {
position: absolute;
top: var(--tabbar-h);
left: 0;
right: 0;
bottom: var(--keybar-h);
background-color: #1a1a1a;
overflow: hidden;
}
.term-pane {
position: absolute;
inset: 0;
overflow: hidden;
}
/* ── Shortcut key bar (bottom) — shown on ALL devices ────────────── */
#keybar {
position: fixed;
bottom: 0;
left: 0;
right: 0;
height: var(--keybar-h);
background-color: #2a2a2a;
border-top: 1px solid #3a3a3a;
display: flex;
flex-direction: row;
overflow-x: auto;
overflow-y: hidden;
z-index: 1000;
gap: 0;
scrollbar-width: thin;
}
#keybar button {
flex: 1 0 auto;
min-width: 48px;
height: var(--keybar-h);
padding: 0 8px;
border: 1px solid #444;
border-top: none;
border-bottom: none;
background-color: #333;
color: #ddd;
font-family: inherit;
font-size: 14px;
cursor: pointer;
border-radius: 0;
transition: background-color 0.12s;
-webkit-user-select: none;
user-select: none;
-webkit-touch-callout: none;
}
#keybar button:active {
background-color: #555;
}
/* Esc is the most-used (interrupt) — make it prominent. */
#keybar button.keybar-btn-primary {
background-color: #5a3a12;
color: #ffcf8f;
font-weight: 600;
min-width: 56px;
}
#keybar button.keybar-btn-primary:active {
background-color: #7a4f18;
} }

View File

@@ -107,7 +107,7 @@ export class TerminalSession {
this.term = new Terminal({ this.term = new Terminal({
scrollback: 5000, scrollback: 5000,
fontFamily: 'Menlo, Consolas, monospace', fontFamily: 'Menlo, Consolas, monospace',
theme: { background: '#1a1a1a', foreground: '#e8e8e8', cursor: '#e8e8e8' }, theme: { background: '#0e0f13', foreground: '#e7e8ec', cursor: '#7c8cff' },
}) })
this.fitAddon = new FitAddon() this.fitAddon = new FitAddon()
this.term.loadAddon(this.fitAddon) this.term.loadAddon(this.fitAddon)