feat(ui): refresh shell, auth, and node visuals
This commit is contained in:
@@ -24,8 +24,7 @@
|
||||
}
|
||||
|
||||
body.theme-dark,
|
||||
body.theme-light,
|
||||
body.theme-blue {
|
||||
body.theme-light {
|
||||
--color-primary-50: 239 246 255;
|
||||
--color-primary-100: 219 234 254;
|
||||
--color-primary-200: 191 219 254;
|
||||
@@ -39,37 +38,6 @@ body.theme-blue {
|
||||
--color-primary-950: 23 37 84;
|
||||
}
|
||||
|
||||
body.theme-green {
|
||||
--color-primary-50: 236 253 245;
|
||||
--color-primary-100: 209 250 229;
|
||||
--color-primary-200: 167 243 208;
|
||||
--color-primary-300: 110 231 183;
|
||||
--color-primary-400: 52 211 153;
|
||||
--color-primary-500: 16 185 129;
|
||||
--color-primary-600: 5 150 105;
|
||||
--color-primary-700: 4 120 87;
|
||||
--color-primary-800: 6 95 70;
|
||||
--color-primary-900: 6 78 59;
|
||||
--color-primary-950: 2 44 34;
|
||||
}
|
||||
|
||||
body.theme-red {
|
||||
--color-primary-50: 254 242 242;
|
||||
--color-primary-100: 254 226 226;
|
||||
--color-primary-200: 254 202 202;
|
||||
--color-primary-300: 252 165 165;
|
||||
--color-primary-400: 248 113 113;
|
||||
--color-primary-500: 239 68 68;
|
||||
--color-primary-600: 220 38 38;
|
||||
--color-primary-700: 185 28 28;
|
||||
--color-primary-800: 153 27 27;
|
||||
--color-primary-900: 127 29 29;
|
||||
--color-primary-950: 69 10 10;
|
||||
}
|
||||
|
||||
body.theme-blue,
|
||||
body.theme-green,
|
||||
body.theme-red,
|
||||
body.theme-dark,
|
||||
body.theme-light {
|
||||
--bs-primary: rgb(var(--color-primary-600));
|
||||
@@ -133,12 +101,47 @@ a {
|
||||
.auth-card {
|
||||
background: color-mix(in srgb, var(--ma-surface-overlay) 92%, transparent);
|
||||
backdrop-filter: blur(14px);
|
||||
border: 1px solid var(--ma-border);
|
||||
}
|
||||
|
||||
body[data-bs-theme="light"] .auth-card {
|
||||
background: color-mix(in srgb, white 58%, var(--ma-surface-base));
|
||||
}
|
||||
|
||||
.auth-shell {
|
||||
background:
|
||||
radial-gradient(circle at top center, rgba(var(--color-primary-500), 0.16), transparent 24%),
|
||||
linear-gradient(180deg, #181c22 0%, #14181e 100%);
|
||||
}
|
||||
|
||||
body[data-bs-theme="light"] .auth-shell {
|
||||
background:
|
||||
radial-gradient(circle at top center, rgba(var(--color-primary-300), 0.28), transparent 22%),
|
||||
linear-gradient(180deg, #f4f7fb 0%, #eceff4 100%);
|
||||
}
|
||||
|
||||
.container-tight {
|
||||
max-width: 26rem;
|
||||
}
|
||||
|
||||
.auth-logo {
|
||||
width: 4rem;
|
||||
height: 4rem;
|
||||
object-fit: cover;
|
||||
border-radius: 1rem;
|
||||
box-shadow: 0 0.75rem 2rem rgba(0, 0, 0, 0.22);
|
||||
}
|
||||
|
||||
.auth-card-tabler {
|
||||
border-radius: 1rem;
|
||||
box-shadow: 0 1.5rem 3.5rem rgba(15, 23, 42, 0.28);
|
||||
}
|
||||
|
||||
.auth-input {
|
||||
min-height: 2.75rem;
|
||||
border-radius: 0.85rem;
|
||||
}
|
||||
|
||||
.auth-brand {
|
||||
background:
|
||||
radial-gradient(circle at top, rgba(var(--color-primary-600), 0.32), transparent 35%),
|
||||
@@ -199,6 +202,28 @@ body[data-bs-theme="light"] .auth-feature {
|
||||
font-size: 1.4rem;
|
||||
}
|
||||
|
||||
.chip-icon-plain {
|
||||
background: transparent;
|
||||
box-shadow: none;
|
||||
color: var(--bs-emphasis-color);
|
||||
}
|
||||
|
||||
.distro-icon {
|
||||
color: var(--bs-emphasis-color);
|
||||
}
|
||||
|
||||
.distro-icon.fl-ubuntu {
|
||||
color: #e95420;
|
||||
}
|
||||
|
||||
.distro-icon.fl-debian {
|
||||
color: #d70a53;
|
||||
}
|
||||
|
||||
.distro-icon.fl-archlinux {
|
||||
color: #1793d1;
|
||||
}
|
||||
|
||||
.content {
|
||||
min-width: 0;
|
||||
min-height: 0;
|
||||
@@ -228,12 +253,6 @@ body[data-bs-theme="light"] .app-sidebar {
|
||||
background: color-mix(in srgb, white 22%, var(--ma-surface-sidebar));
|
||||
}
|
||||
|
||||
.app-sidebar-nav .btn {
|
||||
justify-content: flex-start;
|
||||
align-items: center;
|
||||
gap: 0.4rem;
|
||||
}
|
||||
|
||||
.sidebar-logo {
|
||||
width: 3rem;
|
||||
height: 3rem;
|
||||
@@ -242,6 +261,75 @@ body[data-bs-theme="light"] .app-sidebar {
|
||||
box-shadow: 0 0.75rem 2rem rgba(var(--color-primary-700), 0.18);
|
||||
}
|
||||
|
||||
.app-sidebar-inner {
|
||||
gap: 0.9rem;
|
||||
}
|
||||
|
||||
.sidebar-brand {
|
||||
padding: 0.35rem 0.2rem 0.55rem;
|
||||
}
|
||||
|
||||
.sidebar-brand-title {
|
||||
font-size: 1rem;
|
||||
font-weight: 700;
|
||||
letter-spacing: -0.02em;
|
||||
}
|
||||
|
||||
.sidebar-section-label {
|
||||
padding: 0 0.65rem;
|
||||
font-size: 0.72rem;
|
||||
font-weight: 700;
|
||||
letter-spacing: 0.08em;
|
||||
text-transform: uppercase;
|
||||
color: var(--bs-secondary-color);
|
||||
}
|
||||
|
||||
.app-sidebar-nav {
|
||||
gap: 0.35rem;
|
||||
}
|
||||
|
||||
.app-nav-link {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.8rem;
|
||||
min-height: 2.9rem;
|
||||
padding: 0.75rem 0.85rem;
|
||||
border-radius: 0.95rem;
|
||||
color: var(--bs-secondary-color);
|
||||
font-weight: 600;
|
||||
transition: background-color 0.18s ease, color 0.18s ease, transform 0.18s ease, box-shadow 0.18s ease;
|
||||
}
|
||||
|
||||
.app-nav-link i {
|
||||
width: 1.1rem;
|
||||
font-size: 1.05rem;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.app-nav-link:hover {
|
||||
color: var(--bs-emphasis-color);
|
||||
background: color-mix(in srgb, var(--ma-surface-2) 92%, transparent);
|
||||
transform: translateX(2px);
|
||||
}
|
||||
|
||||
.app-nav-link.is-active {
|
||||
color: #fff;
|
||||
background: linear-gradient(135deg, rgba(var(--color-primary-600), 0.96), rgba(var(--color-primary-700), 0.96));
|
||||
box-shadow: 0 0.9rem 2rem rgba(var(--color-primary-900), 0.2);
|
||||
}
|
||||
|
||||
body[data-bs-theme="light"] .app-nav-link.is-active {
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.app-header {
|
||||
box-shadow: inset 0 -1px 0 var(--ma-border);
|
||||
}
|
||||
|
||||
.app-footer {
|
||||
box-shadow: inset 0 1px 0 var(--ma-border);
|
||||
}
|
||||
|
||||
.min-w-0 {
|
||||
min-width: 0;
|
||||
}
|
||||
@@ -285,6 +373,7 @@ body[data-bs-theme="light"] .app-sidebar {
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 0;
|
||||
border-radius: 0.85rem;
|
||||
}
|
||||
|
||||
.node-chip {
|
||||
@@ -311,6 +400,90 @@ body[data-bs-theme="light"] .app-sidebar {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.kpi-card-featured .card-body {
|
||||
min-height: 12rem;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.kpi-card-label {
|
||||
font-size: 0.76rem;
|
||||
font-weight: 700;
|
||||
letter-spacing: 0.08em;
|
||||
text-transform: uppercase;
|
||||
color: var(--bs-secondary-color);
|
||||
}
|
||||
|
||||
.kpi-card-subtle {
|
||||
margin-top: 0.35rem;
|
||||
font-size: 0.9rem;
|
||||
color: var(--bs-secondary-color);
|
||||
}
|
||||
|
||||
.kpi-card-chip {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
min-height: 2rem;
|
||||
padding: 0.35rem 0.7rem;
|
||||
border-radius: 999px;
|
||||
border: 1px solid var(--ma-border);
|
||||
background: color-mix(in srgb, var(--ma-surface-base) 78%, var(--ma-surface-2));
|
||||
color: var(--bs-secondary-color);
|
||||
font-size: 0.76rem;
|
||||
font-weight: 600;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.kpi-card-featured-value {
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
font-size: clamp(2.3rem, 4vw, 3.15rem);
|
||||
font-weight: 800;
|
||||
line-height: 1;
|
||||
letter-spacing: -0.03em;
|
||||
color: var(--bs-emphasis-color);
|
||||
}
|
||||
|
||||
.kpi-card-featured-trend {
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.7rem;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.kpi-card-trend {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
min-height: 2rem;
|
||||
padding: 0.3rem 0.65rem;
|
||||
border-radius: 999px;
|
||||
font-size: 0.82rem;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.kpi-card-trend.is-up {
|
||||
color: #86efac;
|
||||
background: rgba(20, 83, 45, 0.58);
|
||||
}
|
||||
|
||||
.kpi-card-trend.is-down {
|
||||
color: #fca5a5;
|
||||
background: rgba(127, 29, 29, 0.58);
|
||||
}
|
||||
|
||||
.kpi-card-trend.is-flat {
|
||||
color: #cbd5e1;
|
||||
background: rgba(51, 65, 85, 0.6);
|
||||
}
|
||||
|
||||
.kpi-card-trend-copy {
|
||||
font-size: 0.88rem;
|
||||
color: var(--bs-secondary-color);
|
||||
}
|
||||
|
||||
.kpi-graph {
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
@@ -323,6 +496,13 @@ body[data-bs-theme="light"] .app-sidebar {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.kpi-card-featured .kpi-graph {
|
||||
inset: auto 0 0 0;
|
||||
height: 68%;
|
||||
opacity: 0.92;
|
||||
mask-image: linear-gradient(180deg, transparent 0%, rgba(0, 0, 0, 0.45) 26%, rgba(0, 0, 0, 1) 100%);
|
||||
}
|
||||
|
||||
.node-tile {
|
||||
display: grid;
|
||||
grid-template-columns: 64px minmax(0, 1fr);
|
||||
@@ -382,6 +562,12 @@ body[data-bs-theme="light"] .app-sidebar {
|
||||
font-size: 1rem;
|
||||
}
|
||||
|
||||
.node-brand-icon {
|
||||
width: 3rem;
|
||||
height: 3rem;
|
||||
font-size: 2.1rem;
|
||||
}
|
||||
|
||||
.node-loading-icon {
|
||||
animation: node-icon-spin 1s linear infinite;
|
||||
}
|
||||
@@ -455,6 +641,16 @@ body[data-bs-theme="light"] .app-sidebar {
|
||||
font-size: 1.2rem;
|
||||
}
|
||||
|
||||
.system-summary-icon-plain {
|
||||
width: 3.5rem;
|
||||
height: 3.5rem;
|
||||
font-size: 2.25rem;
|
||||
}
|
||||
|
||||
.distro-icon-lg {
|
||||
font-size: 2.4rem;
|
||||
}
|
||||
|
||||
.system-summary-label {
|
||||
font-size: 0.72rem;
|
||||
font-weight: 700;
|
||||
@@ -515,6 +711,23 @@ body[data-bs-theme="light"] .app-sidebar {
|
||||
background: var(--ma-surface-1);
|
||||
}
|
||||
|
||||
.form-control,
|
||||
.form-select,
|
||||
.btn,
|
||||
.modal-content {
|
||||
border-radius: 0.9rem;
|
||||
}
|
||||
|
||||
.form-control,
|
||||
.form-select {
|
||||
background: color-mix(in srgb, var(--ma-surface-base) 80%, var(--ma-surface-2));
|
||||
}
|
||||
|
||||
body[data-bs-theme="light"] .form-control,
|
||||
body[data-bs-theme="light"] .form-select {
|
||||
background: color-mix(in srgb, white 72%, var(--ma-surface-1));
|
||||
}
|
||||
|
||||
.stat-card,
|
||||
.node-chip,
|
||||
.dashboard-loader > .card,
|
||||
@@ -739,23 +952,159 @@ body[data-bs-theme="light"] .theme-card {
|
||||
background: linear-gradient(135deg, #ffffff, #e2e8f0);
|
||||
}
|
||||
|
||||
.swatch-green {
|
||||
background: linear-gradient(135deg, rgb(16 185 129), rgb(4 120 87));
|
||||
}
|
||||
|
||||
.swatch-red {
|
||||
background: linear-gradient(135deg, rgb(239 68 68), rgb(185 28 28));
|
||||
}
|
||||
|
||||
.swatch-blue {
|
||||
background: linear-gradient(135deg, rgb(59 130 246), rgb(29 78 216));
|
||||
}
|
||||
|
||||
.btn-check:checked + .theme-card {
|
||||
border-color: rgb(var(--color-primary-500));
|
||||
box-shadow: 0 0 0 0.2rem rgba(var(--color-primary-500), 0.2);
|
||||
}
|
||||
|
||||
.uptime-summary-card {
|
||||
background: linear-gradient(180deg, color-mix(in srgb, var(--ma-surface-2) 92%, transparent), var(--ma-surface-1));
|
||||
}
|
||||
|
||||
.uptime-summary-label {
|
||||
font-size: 0.76rem;
|
||||
font-weight: 700;
|
||||
letter-spacing: 0.08em;
|
||||
text-transform: uppercase;
|
||||
color: var(--bs-secondary-color);
|
||||
margin-bottom: 0.6rem;
|
||||
}
|
||||
|
||||
.uptime-summary-value {
|
||||
font-size: clamp(1.8rem, 3vw, 2.5rem);
|
||||
font-weight: 800;
|
||||
line-height: 1;
|
||||
color: var(--bs-emphasis-color);
|
||||
}
|
||||
|
||||
.uptime-monitor-card {
|
||||
display: grid;
|
||||
gap: 1rem;
|
||||
height: 100%;
|
||||
padding: 1.1rem;
|
||||
border: 1px solid var(--ma-border);
|
||||
border-radius: 1.15rem;
|
||||
background: linear-gradient(180deg, color-mix(in srgb, var(--ma-surface-2) 90%, transparent), var(--ma-surface-1));
|
||||
}
|
||||
|
||||
.uptime-monitor-card.is-up {
|
||||
box-shadow: inset 0 0 0 1px rgba(34, 197, 94, 0.12);
|
||||
}
|
||||
|
||||
.uptime-monitor-card.is-down {
|
||||
box-shadow: inset 0 0 0 1px rgba(239, 68, 68, 0.14);
|
||||
}
|
||||
|
||||
.uptime-monitor-head,
|
||||
.uptime-monitor-foot,
|
||||
.uptime-monitor-stat {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 1rem;
|
||||
}
|
||||
|
||||
.uptime-monitor-badge {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
min-width: 4.5rem;
|
||||
min-height: 2rem;
|
||||
padding: 0.35rem 0.75rem;
|
||||
border-radius: 999px;
|
||||
font-size: 0.75rem;
|
||||
font-weight: 700;
|
||||
letter-spacing: 0.04em;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
.uptime-monitor-badge.is-up {
|
||||
color: #86efac;
|
||||
background: rgba(20, 83, 45, 0.55);
|
||||
}
|
||||
|
||||
.uptime-monitor-badge.is-down {
|
||||
color: #fca5a5;
|
||||
background: rgba(127, 29, 29, 0.55);
|
||||
}
|
||||
|
||||
.uptime-monitor-badge.is-pending {
|
||||
color: #cbd5e1;
|
||||
background: rgba(51, 65, 85, 0.65);
|
||||
}
|
||||
|
||||
.uptime-monitor-stats {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||
gap: 0.8rem 1rem;
|
||||
}
|
||||
|
||||
.uptime-monitor-stat {
|
||||
padding: 0.75rem 0.85rem;
|
||||
border-radius: 0.9rem;
|
||||
background: color-mix(in srgb, var(--ma-surface-base) 74%, var(--ma-surface-2));
|
||||
font-size: 0.86rem;
|
||||
}
|
||||
|
||||
.uptime-monitor-stat span,
|
||||
.uptime-monitor-foot {
|
||||
color: var(--bs-secondary-color);
|
||||
}
|
||||
|
||||
.uptime-monitor-stat strong {
|
||||
color: var(--bs-emphasis-color);
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.uptime-check-strip {
|
||||
display: flex;
|
||||
align-items: flex-end;
|
||||
gap: 0.28rem;
|
||||
min-height: 2.25rem;
|
||||
padding: 0.2rem 0;
|
||||
}
|
||||
|
||||
.uptime-check-pill {
|
||||
flex: 1 1 0;
|
||||
min-width: 0;
|
||||
height: 2rem;
|
||||
border-radius: 999px;
|
||||
background: rgba(100, 116, 139, 0.35);
|
||||
}
|
||||
|
||||
.uptime-check-pill.is-up {
|
||||
background: linear-gradient(180deg, rgba(34, 197, 94, 0.95), rgba(22, 163, 74, 0.45));
|
||||
}
|
||||
|
||||
.uptime-check-pill.is-down {
|
||||
background: linear-gradient(180deg, rgba(248, 113, 113, 0.95), rgba(185, 28, 28, 0.5));
|
||||
}
|
||||
|
||||
.uptime-check-pill.is-pending {
|
||||
background: rgba(100, 116, 139, 0.35);
|
||||
}
|
||||
|
||||
.uptime-monitor-foot {
|
||||
font-size: 0.82rem;
|
||||
}
|
||||
|
||||
.uptime-table th {
|
||||
font-size: 0.75rem;
|
||||
font-weight: 700;
|
||||
letter-spacing: 0.08em;
|
||||
text-transform: uppercase;
|
||||
color: var(--bs-secondary-color);
|
||||
}
|
||||
|
||||
body[data-bs-theme="light"] .uptime-monitor-card,
|
||||
body[data-bs-theme="light"] .uptime-summary-card {
|
||||
background: linear-gradient(180deg, color-mix(in srgb, white 76%, var(--ma-surface-1)), var(--ma-surface-1));
|
||||
}
|
||||
|
||||
body[data-bs-theme="light"] .uptime-monitor-stat {
|
||||
background: color-mix(in srgb, white 82%, var(--ma-surface-1));
|
||||
}
|
||||
|
||||
@media (max-width: 991.98px) {
|
||||
.app-shell {
|
||||
flex-direction: column;
|
||||
|
||||
@@ -8,6 +8,8 @@ document.addEventListener("DOMContentLoaded", () => {
|
||||
const dashboardNodes = document.getElementById("dashboard-nodes");
|
||||
const dashboardSearch = document.getElementById("dashboard-search");
|
||||
const authToggle = document.querySelector("[data-auth-toggle]");
|
||||
const themeRadios = document.querySelectorAll('input[name="theme"]');
|
||||
const themeModeInput = document.querySelector('input[name="mode"]');
|
||||
|
||||
const attachXtermConsole = (consoleOutput) => {
|
||||
const wsPath = consoleOutput.dataset.ws;
|
||||
@@ -143,6 +145,7 @@ document.addEventListener("DOMContentLoaded", () => {
|
||||
disk: [],
|
||||
uptime: [],
|
||||
};
|
||||
let previousCpu = null;
|
||||
|
||||
const uptimeLabel = (seconds) => {
|
||||
const days = Math.floor(seconds / 86400);
|
||||
@@ -200,11 +203,21 @@ document.addEventListener("DOMContentLoaded", () => {
|
||||
const ramValue = nodeLive.querySelector('[data-kpi-value="ram"]');
|
||||
const diskValue = nodeLive.querySelector('[data-kpi-value="disk"]');
|
||||
const uptimeValue = nodeLive.querySelector('[data-kpi-value="uptime"]');
|
||||
const cpuTrend = nodeLive.querySelector('[data-kpi-trend="cpu"]');
|
||||
|
||||
if (cpuValue) cpuValue.textContent = `${cpu.toFixed(1)}%`;
|
||||
if (ramValue) ramValue.textContent = `${ram.toFixed(1)}%`;
|
||||
if (diskValue) diskValue.textContent = `${disk.toFixed(1)}%`;
|
||||
if (uptimeValue) uptimeValue.textContent = uptimeLabel(uptime);
|
||||
if (cpuTrend) {
|
||||
const delta = previousCpu === null ? 0 : cpu - previousCpu;
|
||||
const trendClass = delta > 0.15 ? "is-up" : delta < -0.15 ? "is-down" : "is-flat";
|
||||
const trendLabel = `${delta > 0 ? "+" : ""}${delta.toFixed(1)}%`;
|
||||
cpuTrend.classList.remove("is-up", "is-down", "is-flat");
|
||||
cpuTrend.classList.add(trendClass);
|
||||
cpuTrend.textContent = trendLabel;
|
||||
}
|
||||
previousCpu = cpu;
|
||||
|
||||
pushValue("cpu", cpu);
|
||||
pushValue("ram", ram);
|
||||
@@ -294,6 +307,16 @@ document.addEventListener("DOMContentLoaded", () => {
|
||||
syncAuthMode();
|
||||
}
|
||||
|
||||
if (themeModeInput instanceof HTMLInputElement) {
|
||||
themeRadios.forEach((radio) => {
|
||||
radio.addEventListener("change", () => {
|
||||
if (radio instanceof HTMLInputElement && radio.checked) {
|
||||
themeModeInput.value = radio.value;
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
if (typeof bootstrap !== "undefined") {
|
||||
document.querySelectorAll('[data-bs-toggle-tooltip="tooltip"]').forEach((element) => {
|
||||
new bootstrap.Tooltip(element);
|
||||
|
||||
Reference in New Issue
Block a user