Archival commit, newer version exists, will push
This commit is contained in:
commit
b6094834bb
22 files changed
+7369
No files matched your search
+250
@@ -0,0 +1,250 @@
|
||||
:root {
|
||||
--mono: "JetBrains Mono", "IBM Plex Mono", "Cascadia Code", "SF Mono", ui-monospace, Menlo, Consolas, "Liberation Mono", monospace;
|
||||
--bg: #0d1317;
|
||||
--bg2: #121a20;
|
||||
--bg3: #19232b;
|
||||
--line: #25323b;
|
||||
--fg: #cdd6d2;
|
||||
--dim: #7d8d92;
|
||||
--accent: #ff9e3d;
|
||||
--accent-ink: #1a0f02;
|
||||
--up: #62d6a4;
|
||||
--down: #ff6b6b;
|
||||
--warn: #f2c14e;
|
||||
--blue: #6fb1ff;
|
||||
--mag: #c79bff;
|
||||
--cyan: #5fd0e0;
|
||||
--sel: #1d2a33;
|
||||
--sel2: #34495a;
|
||||
--radius: 3px;
|
||||
color-scheme: dark;
|
||||
}
|
||||
:root[data-theme="amber"] {
|
||||
--bg: #120d05; --bg2: #19120a; --bg3: #221910; --line: #3a2c18;
|
||||
--fg: #ecd5a3; --dim: #8f7a4f; --accent: #ffb000; --accent-ink: #1a1000;
|
||||
--up: #b5d96b; --down: #ff7043; --warn: #ffd166; --sel: #2a1f10; --sel2: #5a4624;
|
||||
}
|
||||
:root[data-theme="green"] {
|
||||
--bg: #070b08; --bg2: #0c120d; --bg3: #121b14; --line: #1d3022;
|
||||
--fg: #bfe8c9; --dim: #5f8a69; --accent: #4dff8f; --accent-ink: #02140a;
|
||||
--up: #4dff8f; --down: #ff5f6d; --warn: #e8d44d; --sel: #14241a; --sel2: #2b5a3a;
|
||||
}
|
||||
:root[data-theme="paper"] {
|
||||
--bg: #eef1f0; --bg2: #e4e9e7; --bg3: #d9dfdc; --line: #c3ccc8;
|
||||
--fg: #1c2528; --dim: #66757a; --accent: #b4540a; --accent-ink: #fff7ef;
|
||||
--up: #1d7f5a; --down: #c0392b; --warn: #9a6b00; --blue: #1f5fae; --mag: #7a3fb0; --cyan: #137a88;
|
||||
--sel: #d3dbd8; --sel2: #aebcc4; color-scheme: light;
|
||||
}
|
||||
|
||||
* { box-sizing: border-box; }
|
||||
html, body { height: 100%; }
|
||||
body {
|
||||
margin: 0; background: var(--bg); color: var(--fg);
|
||||
font: 14px/1.5 var(--mono); font-variant-ligatures: none;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
}
|
||||
::selection { background: var(--accent); color: var(--accent-ink); }
|
||||
a { color: var(--accent); text-decoration: none; }
|
||||
a:hover { text-decoration: underline; }
|
||||
button, input, select, textarea { font: inherit; color: inherit; }
|
||||
:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }
|
||||
.dim { color: var(--dim); }
|
||||
.up { color: var(--up); } .down { color: var(--down); } .warn { color: var(--warn); }
|
||||
.hidden { display: none !important; }
|
||||
.right { text-align: right; }
|
||||
.trunc { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; min-width: 0; }
|
||||
|
||||
/* ---------- shell ---------- */
|
||||
#app { display: flex; flex-direction: column; height: 100vh; height: 100dvh; }
|
||||
header.top {
|
||||
display: flex; align-items: center; gap: 18px; padding: 0 20px; height: 44px; flex: none;
|
||||
border-bottom: 1px solid var(--line); background: var(--bg);
|
||||
}
|
||||
.brand { font-weight: 700; color: var(--fg); letter-spacing: 0.02em; white-space: nowrap; }
|
||||
.brand b { color: var(--accent); }
|
||||
nav.tabs { display: flex; gap: 2px; flex: 1; overflow-x: auto; scrollbar-width: none; }
|
||||
nav.tabs button {
|
||||
background: none; border: 0; padding: 0 12px; height: 44px; color: var(--dim); cursor: pointer; white-space: nowrap;
|
||||
border-bottom: 2px solid transparent; margin-bottom: -1px;
|
||||
}
|
||||
nav.tabs button:hover { color: var(--fg); }
|
||||
nav.tabs button.on { color: var(--fg); border-bottom-color: var(--accent); }
|
||||
nav.tabs kbd { color: var(--dim); font-size: 11px; margin-right: 6px; }
|
||||
nav.tabs .count { color: var(--accent); margin-left: 6px; }
|
||||
.top .tools { display: flex; gap: 6px; align-items: center; }
|
||||
main { flex: 1; min-height: 0; position: relative; display: flex; flex-direction: column; }
|
||||
#page { flex: 1; overflow: auto; padding: 20px; }
|
||||
#termview { flex: 1; min-height: 0; display: none; flex-direction: column; }
|
||||
#termview.show { display: flex; }
|
||||
#page.hidden { display: none; }
|
||||
footer.status {
|
||||
display: flex; gap: 20px; align-items: center; padding: 0 20px; height: 28px; flex: none; font-size: 12px;
|
||||
border-top: 1px solid var(--line); background: var(--bg2); color: var(--dim); white-space: nowrap; overflow: hidden;
|
||||
}
|
||||
footer.status .grow { flex: 1; }
|
||||
|
||||
/* ---------- controls ---------- */
|
||||
.btn {
|
||||
background: var(--bg3); border: 1px solid var(--line); border-radius: var(--radius); padding: 3px 12px; cursor: pointer;
|
||||
color: var(--fg); line-height: 1.5; white-space: nowrap;
|
||||
}
|
||||
.btn:hover { border-color: var(--dim); }
|
||||
.btn:active { transform: translateY(1px); }
|
||||
.btn.primary { background: var(--accent); color: var(--accent-ink); border-color: var(--accent); font-weight: 700; }
|
||||
.btn.primary:hover { filter: brightness(1.08); }
|
||||
.btn.danger { color: var(--down); }
|
||||
.btn.danger:hover { border-color: var(--down); }
|
||||
.btn.ghost { background: none; border-color: transparent; color: var(--dim); }
|
||||
.btn.ghost:hover { color: var(--fg); border-color: var(--line); }
|
||||
.btn.sm { padding: 0 8px; font-size: 12px; }
|
||||
.btn[disabled] { opacity: 0.5; cursor: default; }
|
||||
input[type=text], input[type=password], input[type=number], input[type=search], select, textarea {
|
||||
background: var(--bg2); border: 1px solid var(--line); border-radius: var(--radius); padding: 4px 8px; width: 100%;
|
||||
}
|
||||
input:focus, select:focus, textarea:focus { border-color: var(--accent); outline: none; }
|
||||
textarea { resize: vertical; min-height: 64px; }
|
||||
input[type=checkbox] { accent-color: var(--accent); width: 16px; height: 16px; vertical-align: middle; }
|
||||
select { appearance: none; background-image: linear-gradient(45deg, transparent 50%, var(--dim) 50%), linear-gradient(135deg, var(--dim) 50%, transparent 50%);
|
||||
background-position: calc(100% - 14px) 50%, calc(100% - 9px) 50%; background-size: 5px 5px; background-repeat: no-repeat; padding-right: 26px; }
|
||||
|
||||
/* ---------- page heads ---------- */
|
||||
.prompt { display: flex; align-items: baseline; gap: 10px; flex-wrap: wrap; margin-bottom: 4px; }
|
||||
.prompt .ps1 { color: var(--accent); }
|
||||
.prompt .ps1 i { color: var(--dim); font-style: normal; }
|
||||
.cursor { display: inline-block; width: 0.6em; height: 1.05em; background: var(--accent); vertical-align: text-bottom; animation: blink 1.1s steps(1) infinite; }
|
||||
@keyframes blink { 50% { opacity: 0; } }
|
||||
.summary { display: flex; gap: 22px; flex-wrap: wrap; margin: 6px 0 16px; }
|
||||
.toolbar { display: flex; gap: 8px; align-items: center; margin-bottom: 16px; flex-wrap: wrap; }
|
||||
.toolbar input[type=search] { max-width: 280px; }
|
||||
.toolbar .grow { flex: 1; }
|
||||
|
||||
/* ---------- dashboard ---------- */
|
||||
.group { margin-bottom: 22px; }
|
||||
.group h2 { font-size: 14px; font-weight: 400; margin: 0 0 4px; color: var(--dim); display: flex; gap: 10px; align-items: center; }
|
||||
.group h2::before { content: "┌─"; color: var(--line); }
|
||||
.group h2::after { content: ""; flex: 1; border-top: 1px solid var(--line); }
|
||||
.svc {
|
||||
display: grid; align-items: center; column-gap: 14px; padding: 5px 8px; border-radius: var(--radius); cursor: pointer;
|
||||
grid-template-columns: 1.5ch minmax(12ch, 1.1fr) minmax(0, 1.6fr) 8ch 8ch 31ch 13ch 188px;
|
||||
}
|
||||
.svc:hover { background: var(--sel); }
|
||||
.svc.open { background: var(--sel); }
|
||||
.svc .led { color: var(--dim); font-size: 12px; }
|
||||
.svc.s-up .led { color: var(--up); }
|
||||
.svc.s-down .led { color: var(--down); animation: pulse 2.2s ease-in-out infinite; }
|
||||
.svc.s-retry .led { color: var(--warn); }
|
||||
.svc.s-paused { opacity: 0.55; }
|
||||
@keyframes pulse { 50% { opacity: 0.35; } }
|
||||
.svc .name { font-weight: 700; }
|
||||
.svc .addr { color: var(--dim); }
|
||||
.svc .spark { letter-spacing: 0; white-space: pre; overflow: hidden; }
|
||||
.svc .spark .x { color: var(--down); }
|
||||
.svc .spark .ok { color: var(--up); }
|
||||
.svc .acts { display: flex; gap: 4px; opacity: 0; justify-content: flex-end; }
|
||||
.svc:hover .acts, .svc.open .acts, .svc:focus-within .acts { opacity: 1; }
|
||||
.detail { padding: 6px 8px 14px 3.4ch; background: var(--sel); border-radius: 0 0 var(--radius) var(--radius); margin: -2px 0 6px; }
|
||||
.detail dl { display: grid; grid-template-columns: max-content 1fr; gap: 2px 18px; margin: 0 0 10px; }
|
||||
.detail dt { color: var(--dim); }
|
||||
.detail dd { margin: 0; overflow-wrap: anywhere; }
|
||||
.strip { display: flex; gap: 1px; height: 20px; align-items: stretch; margin: 6px 0 2px; }
|
||||
.strip i { flex: 1; background: var(--line); min-width: 2px; }
|
||||
.strip i.g { background: var(--up); } .strip i.y { background: var(--warn); } .strip i.r { background: var(--down); }
|
||||
.strip-legend { display: flex; justify-content: space-between; color: var(--dim); font-size: 12px; }
|
||||
.empty { border: 1px dashed var(--line); border-radius: var(--radius); padding: 28px; text-align: center; color: var(--dim); }
|
||||
.empty p { margin: 4px 0 14px; }
|
||||
|
||||
/* ---------- tables ---------- */
|
||||
table.t { width: 100%; border-collapse: collapse; }
|
||||
table.t th { text-align: left; font-weight: 400; color: var(--dim); padding: 4px 10px; border-bottom: 1px solid var(--line); white-space: nowrap; }
|
||||
table.t td { padding: 5px 10px; border-bottom: 1px solid var(--line); vertical-align: top; }
|
||||
table.t tr.row:hover { background: var(--sel); }
|
||||
table.t td.acts { white-space: nowrap; text-align: right; }
|
||||
.chip { display: inline-block; padding: 0 7px; border: 1px solid var(--line); border-radius: 99px; font-size: 12px; color: var(--dim); }
|
||||
.chip.down, .chip.hostkey, .chip.ssh_fail, .chip.login_fail { color: var(--down); border-color: var(--down); }
|
||||
.chip.up { color: var(--up); border-color: var(--up); }
|
||||
.chip.tls { color: var(--warn); border-color: var(--warn); }
|
||||
.chip.ssh { color: var(--cyan); border-color: var(--cyan); }
|
||||
|
||||
/* ---------- terminals ---------- */
|
||||
.termbar { display: flex; align-items: stretch; gap: 0; border-bottom: 1px solid var(--line); background: var(--bg2); flex: none; overflow-x: auto; scrollbar-width: none; }
|
||||
.termbar .tab { display: flex; align-items: center; gap: 8px; padding: 0 10px 0 14px; height: 34px; cursor: pointer; color: var(--dim); border-right: 1px solid var(--line); white-space: nowrap; }
|
||||
.termbar .tab.on { background: var(--bg); color: var(--fg); box-shadow: inset 0 -2px 0 var(--accent); }
|
||||
.termbar .tab .dot { font-size: 11px; }
|
||||
.termbar .tab .dot.connected { color: var(--up); } .termbar .tab .dot.connecting { color: var(--warn); } .termbar .tab .dot.closed, .termbar .tab .dot.error { color: var(--down); }
|
||||
.termbar .tab button { background: none; border: 0; cursor: pointer; color: var(--dim); padding: 0 4px; border-radius: 2px; }
|
||||
.termbar .tab button:hover { color: var(--fg); background: var(--bg3); }
|
||||
.termbar .spacer { flex: 1; }
|
||||
.termbar .tools { display: flex; align-items: center; gap: 6px; padding: 0 10px; }
|
||||
.panes { flex: 1; min-height: 0; position: relative; background: var(--bg); }
|
||||
.pane { position: absolute; inset: 0; padding: 8px 0 4px 12px; display: none; }
|
||||
.pane.on { display: block; }
|
||||
.pane .xterm { height: 100%; }
|
||||
.pane .xterm-viewport { background: transparent !important; }
|
||||
.term-empty { padding: 24px; color: var(--dim); }
|
||||
.term-empty .hostlist { margin-top: 14px; display: flex; flex-direction: column; gap: 2px; max-width: 520px; }
|
||||
.term-empty .hostlist button { text-align: left; background: none; border: 0; padding: 4px 8px; cursor: pointer; border-radius: var(--radius); }
|
||||
.term-empty .hostlist button:hover { background: var(--sel); }
|
||||
|
||||
/* ---------- login ---------- */
|
||||
.login { max-width: 560px; margin: 12vh auto 0; padding: 0 20px; }
|
||||
.login h1 { font-size: 14px; margin: 0 0 18px; font-weight: 700; }
|
||||
.login h1 b { color: var(--accent); }
|
||||
.login p { color: var(--dim); margin: 0 0 18px; }
|
||||
.login label { display: flex; align-items: center; gap: 10px; margin-bottom: 10px; }
|
||||
.login label span { width: 18ch; color: var(--dim); flex: none; }
|
||||
.login .err { color: var(--down); min-height: 1.5em; margin: 6px 0; }
|
||||
|
||||
/* ---------- modal / palette / toast ---------- */
|
||||
.overlay { position: fixed; inset: 0; background: rgba(4, 8, 10, 0.66); display: flex; align-items: flex-start; justify-content: center; padding: 8vh 16px 16px; z-index: 50; overflow: auto; }
|
||||
:root[data-theme="paper"] .overlay { background: rgba(30, 40, 44, 0.4); }
|
||||
.modal { background: var(--bg); border: 1px solid var(--dim); border-radius: var(--radius); width: 100%; max-width: 640px; box-shadow: 0 18px 60px rgba(0, 0, 0, 0.5); }
|
||||
.modal header { padding: 10px 16px; border-bottom: 1px solid var(--line); display: flex; justify-content: space-between; align-items: center; }
|
||||
.modal header h3 { margin: 0; font-size: 14px; font-weight: 700; }
|
||||
.modal .body { padding: 16px; display: flex; flex-direction: column; gap: 12px; }
|
||||
.modal footer { padding: 10px 16px; border-top: 1px solid var(--line); display: flex; gap: 8px; justify-content: flex-end; flex-wrap: wrap; }
|
||||
.modal footer .grow { flex: 1; display: flex; gap: 8px; }
|
||||
.field { display: flex; flex-direction: column; gap: 3px; }
|
||||
.field > label { color: var(--dim); }
|
||||
.field .hint { color: var(--dim); font-size: 12px; }
|
||||
.field.check { flex-direction: row; align-items: center; gap: 10px; }
|
||||
.field.check label { color: var(--fg); }
|
||||
.grid2 { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; }
|
||||
.form-error { color: var(--down); min-height: 1.4em; }
|
||||
.palette { background: var(--bg); border: 1px solid var(--dim); border-radius: var(--radius); width: 100%; max-width: 620px; box-shadow: 0 18px 60px rgba(0, 0, 0, 0.5); }
|
||||
.palette input { border: 0; border-bottom: 1px solid var(--line); border-radius: 0; padding: 10px 16px; background: transparent; }
|
||||
.palette ul { list-style: none; margin: 0; padding: 4px; max-height: 50vh; overflow: auto; }
|
||||
.palette li { display: flex; justify-content: space-between; gap: 16px; padding: 5px 12px; border-radius: var(--radius); cursor: pointer; }
|
||||
.palette li.on { background: var(--sel2); }
|
||||
.palette li .hint { color: var(--dim); }
|
||||
.palette .none { padding: 12px 16px; color: var(--dim); }
|
||||
#toasts { position: fixed; right: 16px; bottom: 44px; display: flex; flex-direction: column; gap: 8px; z-index: 80; max-width: min(420px, calc(100vw - 32px)); }
|
||||
.toast { background: var(--bg3); border: 1px solid var(--line); border-left: 3px solid var(--accent); padding: 8px 12px; border-radius: var(--radius); box-shadow: 0 6px 24px rgba(0, 0, 0, 0.4); animation: tin 0.16s ease-out; }
|
||||
.toast.err { border-left-color: var(--down); }
|
||||
@keyframes tin { from { transform: translateY(6px); opacity: 0; } }
|
||||
|
||||
.section { margin-bottom: 30px; max-width: 760px; }
|
||||
.section h2 { font-size: 14px; margin: 0 0 8px; font-weight: 700; }
|
||||
.section h2::before { content: "# "; color: var(--accent); }
|
||||
.section p { color: var(--dim); margin: 0 0 10px; }
|
||||
.row { display: flex; gap: 8px; align-items: center; flex-wrap: wrap; margin-bottom: 8px; }
|
||||
.row > .grow { flex: 1; min-width: 180px; }
|
||||
.themes { display: flex; gap: 8px; flex-wrap: wrap; }
|
||||
.themes button { display: flex; align-items: center; gap: 8px; }
|
||||
.themes .sw { width: 12px; height: 12px; border-radius: 50%; border: 1px solid var(--line); }
|
||||
|
||||
/* ---------- small screens ---------- */
|
||||
@media (max-width: 900px) {
|
||||
.svc { grid-template-columns: 1.5ch 1fr 8ch 8ch 150px; row-gap: 0; }
|
||||
.svc .addr, .svc .spark, .svc .since { display: none; }
|
||||
#page { padding: 14px; }
|
||||
header.top { padding: 0 12px; gap: 10px; }
|
||||
.grid2 { grid-template-columns: 1fr; }
|
||||
nav.tabs kbd { display: none; }
|
||||
.login label { flex-direction: column; align-items: stretch; gap: 3px; }
|
||||
.login label span { width: auto; }
|
||||
.svc .acts { opacity: 1; }
|
||||
footer.status .hide-s { display: none; }
|
||||
}
|
||||
@media (prefers-reduced-motion: reduce) {
|
||||
.cursor, .svc.s-down .led, .toast { animation: none; }
|
||||
}
|
||||
Reference in new issue
Block a user