From 55bc38577ceb67175e95d47bdf2e66affe401060 Mon Sep 17 00:00:00 2001 From: 0x1d Date: Tue, 14 Oct 2025 10:00:55 +0200 Subject: [PATCH] feat: improve terminal and monitoring styling --- public/scripts/components/DrawerComponent.js | 7 + .../components/MonitoringViewComponent.js | 3 +- public/styles/main.css | 196 +++++++++++++++++- 3 files changed, 198 insertions(+), 8 deletions(-) diff --git a/public/scripts/components/DrawerComponent.js b/public/scripts/components/DrawerComponent.js index 1bcef9d..e0d171e 100644 --- a/public/scripts/components/DrawerComponent.js +++ b/public/scripts/components/DrawerComponent.js @@ -130,10 +130,17 @@ class DrawerComponent { // Open drawer this.detailsDrawer.classList.add('open'); + // Inform terminal container that the drawer is open for alignment + if (this.terminalPanelContainer) { + this.terminalPanelContainer.classList.add('drawer-open'); + } } closeDrawer() { if (this.detailsDrawer) this.detailsDrawer.classList.remove('open'); + if (this.terminalPanelContainer) { + this.terminalPanelContainer.classList.remove('drawer-open'); + } // Call close callback if provided if (this.onCloseCallback) { diff --git a/public/scripts/components/MonitoringViewComponent.js b/public/scripts/components/MonitoringViewComponent.js index a829bd0..f0d7808 100644 --- a/public/scripts/components/MonitoringViewComponent.js +++ b/public/scripts/components/MonitoringViewComponent.js @@ -354,10 +354,11 @@ class MonitoringViewComponent extends Component { return this.renderNodeCard(nodeData); }).join(''); + const nodeCount = nodeResources.size; container.innerHTML = `

🖥️ Node Resource Details

-
+
${nodesHtml}
diff --git a/public/styles/main.css b/public/styles/main.css index 68b7ba0..7b4089c 100644 --- a/public/styles/main.css +++ b/public/styles/main.css @@ -3374,27 +3374,66 @@ select.param-input:focus { inset: 0; display: flex; align-items: flex-end; - justify-content: center; + justify-content: center; /* bottom-centered by default */ z-index: 1001; pointer-events: none; } +/* When the right drawer is open, dock the terminal to the right and offset by drawer width */ +.terminal-panel-container.drawer-open { + /* Bottom-aligned; keep panel centered while reserving space for drawer */ + align-items: flex-end; + justify-content: center; + /* reserve space equal to drawer width */ + margin-right: clamp(33.333vw, 650px, 90vw); +} + .terminal-panel { - position: relative; - width: min(720px, 90vw); + position: fixed; /* lock to viewport to avoid container reflow */ + left: 50%; + bottom: 1.5rem; + width: 33.333vw; /* 1/3 of the screen by default */ height: min(45vh, 520px); max-height: 65vh; background: var(--bg-primary); color: var(--text-primary); border: 1px solid var(--border-primary); box-shadow: 0 18px 40px rgba(0,0,0,0.35); - transform: translateY(32px); + transform: translateX(-50%); opacity: 0; transition: transform 0.25s ease, opacity 0.25s ease; border-radius: 12px; pointer-events: auto; display: flex; flex-direction: column; + z-index: 1002; +} + +/* Desktop layout: terminal takes 1/3 of the screen and fills height when docked */ +@media (min-width: 1024px) { + .terminal-panel-container.drawer-open .terminal-panel { + /* Keep terminal width EXACTLY the same as non-drawer state */ + width: 33.333vw; + max-width: none; + /* Keep terminal height consistent with non-docked state */ + height: min(45vh, 520px); + max-height: 65vh; + border-radius: 12px; + /* Keep same centering transform to avoid jump */ + } +} + +/* Mobile layout: terminal spans full width */ +@media (max-width: 1023px) { + .terminal-panel-container { + margin-right: 0; + justify-content: center; + align-items: flex-end; + } + .terminal-panel { + width: 100vw; + max-width: 100vw; + } } .terminal-panel.minimized { @@ -3402,7 +3441,7 @@ select.param-input:focus { } .terminal-panel.visible { - transform: translateY(0); + transform: translateX(-50%); opacity: 1; } @@ -4342,6 +4381,8 @@ html { display: flex; flex-direction: column; gap: 1.5rem; + flex: 1; + min-height: 0; } /* Cluster Summary Styles */ @@ -4463,17 +4504,90 @@ html { } /* Nodes Monitoring Styles */ +.nodes-monitoring { + flex: 1; + min-height: 0; + display: flex; + flex-direction: column; +} + +.nodes-monitoring-content { + flex: 1; + min-height: 0; + display: flex; + flex-direction: column; +} + .nodes-monitoring-content h3 { color: var(--text-primary); margin: 0 0 1rem 0; font-size: 1.25rem; font-weight: 600; + flex-shrink: 0; } .nodes-grid { display: grid; - grid-template-columns: repeat(auto-fill, minmax(300px, 1fr)); gap: 1rem; + /* Default desktop grid shows 5 items per row */ + grid-template-columns: repeat(5, 1fr); + flex: 1; + min-height: 0; + overflow-y: auto; +} + +/* Dynamic grid layouts based on number of items */ +.nodes-grid[data-item-count="1"] { + grid-template-columns: 1fr; + grid-template-rows: 1fr; + justify-items: center; +} + +.nodes-grid[data-item-count="2"] { + grid-template-columns: repeat(2, 1fr); + grid-template-rows: 1fr; +} + +.nodes-grid[data-item-count="3"] { + grid-template-columns: repeat(3, 1fr); + grid-template-rows: 1fr; +} + +.nodes-grid[data-item-count="4"] { + grid-template-columns: repeat(2, 1fr); + grid-template-rows: repeat(2, 1fr); +} + +.nodes-grid[data-item-count="5"], +.nodes-grid[data-item-count="6"] { + grid-template-columns: repeat(5, 1fr); +} + +.nodes-grid[data-item-count="7"], +.nodes-grid[data-item-count="8"] { + grid-template-columns: repeat(5, 1fr); +} + +.nodes-grid[data-item-count="9"] { + grid-template-columns: repeat(5, 1fr); +} + +.nodes-grid[data-item-count="10"], +.nodes-grid[data-item-count="11"], +.nodes-grid[data-item-count="12"] { + grid-template-columns: repeat(5, 1fr); +} + +/* For more than 12 items, use auto-fit with reasonable minimum */ +.nodes-grid[data-item-count="13"], +.nodes-grid[data-item-count="14"], +.nodes-grid[data-item-count="15"], +.nodes-grid[data-item-count="16"] { + grid-template-columns: repeat(5, 1fr); +} + +.nodes-grid[data-item-count="17"] { + grid-template-columns: repeat(5, 1fr); } .node-card { @@ -4762,16 +4876,84 @@ html { border-bottom: 1px solid var(--border-primary); } +/* Themed Scrollbars (Global and Components) */ +/* Firefox */ +* { + scrollbar-width: thin; /* auto | thin | none */ + scrollbar-color: var(--border-secondary) var(--bg-tertiary); /* thumb track */ +} + +/* WebKit (Chrome, Edge, Safari) */ +/* Global default */ +::-webkit-scrollbar { + width: 10px; + height: 10px; +} +::-webkit-scrollbar-track { + background: var(--bg-tertiary); + border-radius: 8px; +} +::-webkit-scrollbar-thumb { + background: var(--border-secondary); + border-radius: 8px; + border: 2px solid var(--bg-tertiary); /* creates padding and rounded effect */ +} +::-webkit-scrollbar-thumb:hover { + background: var(--border-hover); +} + +/* Terminal panel body - slightly thinner */ +.terminal-body { + scrollbar-width: thin; +} +.terminal-body::-webkit-scrollbar { + width: 8px; +} +.terminal-body::-webkit-scrollbar-thumb { + background: var(--border-secondary); +} + +/* Drawer content area */ +.details-drawer-content { + scrollbar-width: thin; +} +.details-drawer-content::-webkit-scrollbar { + width: 10px; +} +.details-drawer-content::-webkit-scrollbar-thumb { + background: var(--border-secondary); +} + /* Responsive Design */ @media (max-width: 768px) { .summary-stats { grid-template-columns: 1fr; } - .nodes-grid { + /* Mobile grid layouts - simplified for smaller screens but still maximize vertical space */ + .nodes-grid[data-item-count="1"] { grid-template-columns: 1fr; + grid-template-rows: 1fr; + justify-items: center; } + .nodes-grid[data-item-count="2"] { grid-template-columns: repeat(2, 1fr); grid-template-rows: 1fr; } + .nodes-grid[data-item-count="3"], + .nodes-grid[data-item-count="4"] { grid-template-columns: repeat(2, 1fr); grid-template-rows: repeat(2, 1fr); } + .nodes-grid[data-item-count="5"], + .nodes-grid[data-item-count="6"], + .nodes-grid[data-item-count="7"], + .nodes-grid[data-item-count="8"], + .nodes-grid[data-item-count="9"], + .nodes-grid[data-item-count="10"], + .nodes-grid[data-item-count="11"], + .nodes-grid[data-item-count="12"], + .nodes-grid[data-item-count="13"], + .nodes-grid[data-item-count="14"], + .nodes-grid[data-item-count="15"], + .nodes-grid[data-item-count="16"], + .nodes-grid[data-item-count="17"] { grid-template-columns: repeat(2, 1fr); grid-template-rows: repeat(auto-fit, 1fr); } + .monitoring-header { flex-direction: column; gap: 1rem;