Dashboard polish: pie charts, CPU bars, lock icon, header shift, toggle switches
- Add pie chart recoloring (vibrant theme colors for System donuts) - Add system legend color matching for donut chart legends - Add lock button state toggling (locked/unlocked icon via MutationObserver) - Add Tailscale light SVG icon replacement in sidebar - Fix horizontal scrollbar with overflow-x: hidden - Fix header not shifting with sidebar (add #header to margin-left transition) - Fix dashboard double-blur (disable stacking backdrop-filter on tables) - Simplify toggle button style (transparent bg, hover-only highlight) - Style CPU bars with color-coded gradients (green/orange/red) - Style donut charts with thinner ring and opaque center - Style toggle switches with glass appearance - Style card header control icons (transparent, white) - Force white text in Docker dashboard view Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
171
sidebar.js
171
sidebar.js
@@ -38,10 +38,34 @@
|
||||
menu.appendChild(btn);
|
||||
}
|
||||
|
||||
// --- Lock button icon state ---
|
||||
initLockButton();
|
||||
|
||||
// --- Search overlay (delayed to wait for search plugin init) ---
|
||||
setTimeout(initSearchOverlay, 800);
|
||||
}
|
||||
|
||||
function initLockButton() {
|
||||
var lockItem = document.querySelector('.nav-item.LockButton');
|
||||
if (!lockItem) return;
|
||||
var lockLink = lockItem.querySelector('a');
|
||||
if (!lockLink) return;
|
||||
|
||||
function updateLockState() {
|
||||
var title = lockLink.getAttribute('title') || '';
|
||||
if (title.toLowerCase().indexOf('unlock') > -1) {
|
||||
lockItem.classList.add('is-locked');
|
||||
} else {
|
||||
lockItem.classList.remove('is-locked');
|
||||
}
|
||||
}
|
||||
|
||||
updateLockState();
|
||||
|
||||
var observer = new MutationObserver(updateLockState);
|
||||
observer.observe(lockLink, { attributes: true, attributeFilter: ['title'] });
|
||||
}
|
||||
|
||||
function initSearchOverlay() {
|
||||
if (!window.jQuery) return;
|
||||
|
||||
@@ -319,12 +343,26 @@
|
||||
observer.observe(target, { childList: true, subtree: true });
|
||||
}
|
||||
|
||||
// Replace Tailscale sidebar icon with light SVG
|
||||
function replaceTailscaleIcon() {
|
||||
var imgs = document.querySelectorAll('img[alt="Tailscale"]');
|
||||
imgs.forEach(function(img) {
|
||||
var url = CDN_SVG + '/tailscale-light.svg';
|
||||
if (img.getAttribute('src') !== url) {
|
||||
img.src = url;
|
||||
img.removeAttribute('onerror');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Initialize when DOM is ready
|
||||
function initIcons() {
|
||||
// Initial replacement
|
||||
setTimeout(replaceIcons, 500);
|
||||
setTimeout(replaceTailscaleIcon, 500);
|
||||
// Second pass after FolderView finishes its DOM work
|
||||
setTimeout(replaceIcons, 2000);
|
||||
setTimeout(replaceTailscaleIcon, 2000);
|
||||
// Start watching for future changes
|
||||
startObserver();
|
||||
}
|
||||
@@ -335,3 +373,136 @@
|
||||
initIcons();
|
||||
}
|
||||
})();
|
||||
|
||||
// =============================================================
|
||||
// Pie Chart Recoloring — vibrant theme colors for System donuts
|
||||
// =============================================================
|
||||
(function() {
|
||||
'use strict';
|
||||
|
||||
// Unraid's muted defaults → vibrant theme replacements
|
||||
var COLOR_MAP = {
|
||||
'rgb(68,119,170)': '#7EB8DA', // accent blue (used)
|
||||
'rgb(204,204,204)': 'rgba(255,255,255,0.10)', // free → subtle
|
||||
'rgb(34,136,51)': '#4ade80', // green
|
||||
'rgb(170,68,153)': '#f97316', // purple → orange
|
||||
'rgb(238,102,119)': '#ef4444', // red
|
||||
'rgb(0,153,136)': '#22d3ee', // teal → cyan
|
||||
'rgb(221,204,119)': '#facc15', // yellow
|
||||
'rgb(136,34,85)': '#f87171', // dark red → light red
|
||||
'rgb(17,119,51)': '#22c55e', // dark green → bright green
|
||||
'rgb(51,34,136)': '#818cf8', // dark purple → indigo
|
||||
'rgb(102,153,204)': '#93c5fd' // light blue
|
||||
};
|
||||
|
||||
function recolorPie(pie) {
|
||||
var style = pie.getAttribute('style');
|
||||
if (!style || style.indexOf('conic-gradient') === -1) return;
|
||||
|
||||
var newStyle = style;
|
||||
var keys = Object.keys(COLOR_MAP);
|
||||
for (var i = 0; i < keys.length; i++) {
|
||||
// Replace with global flag via split/join
|
||||
newStyle = newStyle.split(keys[i]).join(COLOR_MAP[keys[i]]);
|
||||
}
|
||||
|
||||
if (newStyle !== style) {
|
||||
pie.setAttribute('style', newStyle);
|
||||
}
|
||||
}
|
||||
|
||||
function recolorAll() {
|
||||
var pies = document.querySelectorAll('div.pie');
|
||||
pies.forEach(recolorPie);
|
||||
}
|
||||
|
||||
function startObserver() {
|
||||
var target = document.getElementById('displaybox') || document.body;
|
||||
var observer = new MutationObserver(function(mutations) {
|
||||
for (var i = 0; i < mutations.length; i++) {
|
||||
var m = mutations[i];
|
||||
if (m.type === 'attributes' && m.attributeName === 'style') {
|
||||
var el = m.target;
|
||||
if (el.classList && el.classList.contains('pie')) {
|
||||
recolorPie(el);
|
||||
}
|
||||
}
|
||||
if (m.type === 'childList' && m.addedNodes.length > 0) {
|
||||
recolorAll();
|
||||
}
|
||||
}
|
||||
});
|
||||
observer.observe(target, {
|
||||
childList: true,
|
||||
subtree: true,
|
||||
attributes: true,
|
||||
attributeFilter: ['style']
|
||||
});
|
||||
}
|
||||
|
||||
function init() {
|
||||
setTimeout(recolorAll, 600);
|
||||
setTimeout(recolorAll, 2000);
|
||||
startObserver();
|
||||
}
|
||||
|
||||
if (document.readyState === 'loading') {
|
||||
document.addEventListener('DOMContentLoaded', init);
|
||||
} else {
|
||||
init();
|
||||
}
|
||||
})();
|
||||
|
||||
// =============================================================
|
||||
// System Legend Colors — match pie segment colors in legends
|
||||
// =============================================================
|
||||
(function() {
|
||||
'use strict';
|
||||
|
||||
// Unraid default legend colors → vibrant theme colors
|
||||
var LEGEND_MAP = {
|
||||
'rgb(68, 119, 170)': '#7EB8DA',
|
||||
'rgb(204, 204, 204)': 'rgba(255,255,255,0.35)',
|
||||
'rgb(34, 136, 51)': '#4ade80',
|
||||
'rgb(170, 68, 153)': '#f97316',
|
||||
'rgb(238, 102, 119)': '#ef4444',
|
||||
'rgb(0, 153, 136)': '#22d3ee',
|
||||
'rgb(221, 204, 119)': '#facc15',
|
||||
'rgb(136, 34, 85)': '#f87171',
|
||||
'rgb(17, 119, 51)': '#22c55e',
|
||||
'rgb(51, 34, 136)': '#818cf8',
|
||||
'rgb(102, 153, 204)': '#93c5fd'
|
||||
};
|
||||
|
||||
function recolorLegends() {
|
||||
var icons = document.querySelectorAll('#dynamic i.fa-circle');
|
||||
icons.forEach(function(icon) {
|
||||
var currentColor = icon.style.color;
|
||||
if (!currentColor) return;
|
||||
var mapped = LEGEND_MAP[currentColor];
|
||||
if (mapped) {
|
||||
icon.style.setProperty('color', mapped, 'important');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function startObserver() {
|
||||
var target = document.getElementById('dynamic') || document.getElementById('displaybox') || document.body;
|
||||
var observer = new MutationObserver(function() {
|
||||
recolorLegends();
|
||||
});
|
||||
observer.observe(target, { childList: true, subtree: true });
|
||||
}
|
||||
|
||||
function init() {
|
||||
setTimeout(recolorLegends, 700);
|
||||
setTimeout(recolorLegends, 2500);
|
||||
startObserver();
|
||||
}
|
||||
|
||||
if (document.readyState === 'loading') {
|
||||
document.addEventListener('DOMContentLoaded', init);
|
||||
} else {
|
||||
init();
|
||||
}
|
||||
})();
|
||||
|
||||
169
style.css
169
style.css
@@ -3,6 +3,11 @@
|
||||
Mountain wallpaper + frosted glass cards
|
||||
============================================ */
|
||||
|
||||
/* --- Prevent horizontal scrollbar --- */
|
||||
html {
|
||||
overflow-x: hidden;
|
||||
}
|
||||
|
||||
/* --- CSS Variables --- */
|
||||
:root {
|
||||
/* Accent: cool steel blue to match B&W mountains */
|
||||
@@ -180,18 +185,17 @@ body::before {
|
||||
transition: transform 0.3s cubic-bezier(0.4, 0, 0.2, 1);
|
||||
}
|
||||
|
||||
/* Expanded: chevron in visible circle, rotated to point left */
|
||||
/* Expanded: round hover highlight, rotated to point left */
|
||||
html.sidebar-expanded #sidebar-toggle-btn {
|
||||
width: 36px !important;
|
||||
height: 36px !important;
|
||||
box-sizing: border-box !important;
|
||||
background: rgba(255, 255, 255, 0.06) !important;
|
||||
border: 1px solid rgba(255, 255, 255, 0.10) !important;
|
||||
background: transparent !important;
|
||||
border: none !important;
|
||||
}
|
||||
|
||||
html.sidebar-expanded #sidebar-toggle-btn:hover {
|
||||
background: rgba(255, 255, 255, 0.12) !important;
|
||||
border-color: rgba(255, 255, 255, 0.20) !important;
|
||||
background: rgba(255, 255, 255, 0.10) !important;
|
||||
}
|
||||
|
||||
html.sidebar-expanded #sidebar-toggle-btn svg {
|
||||
@@ -323,6 +327,7 @@ html.sidebar-expanded #sidebar-toggle-btn svg {
|
||||
.Theme--sidebar .nav-item.LogButton a:before { content: "\f0f6" !important; }
|
||||
.Theme--sidebar .nav-item.HelpButton a:before { content: "\f059" !important; }
|
||||
.Theme--sidebar .nav-item.LockButton a:before { content: "\f09c" !important; font-family: FontAwesome !important; }
|
||||
.Theme--sidebar .nav-item.LockButton.is-locked a:before { content: "\f023" !important; }
|
||||
|
||||
/* --- EXPANDED SIDEBAR ---
|
||||
Compound selectors: both classes on <html> */
|
||||
@@ -382,6 +387,7 @@ html.sidebar-expanded.Theme--sidebar .nav-tile.right .nav-item a {
|
||||
}
|
||||
|
||||
/* --- Content area shifts for sidebar (push, not overlap) --- */
|
||||
#header,
|
||||
#displaybox,
|
||||
#footer,
|
||||
#copyright {
|
||||
@@ -389,6 +395,7 @@ html.sidebar-expanded.Theme--sidebar .nav-tile.right .nav-item a {
|
||||
transition: margin-left 0.3s cubic-bezier(0.4, 0, 0.2, 1) !important;
|
||||
}
|
||||
|
||||
html.sidebar-expanded.Theme--sidebar #header,
|
||||
html.sidebar-expanded.Theme--sidebar #displaybox,
|
||||
html.sidebar-expanded.Theme--sidebar #footer,
|
||||
html.sidebar-expanded.Theme--sidebar #copyright {
|
||||
@@ -936,13 +943,21 @@ div.tile {
|
||||
overflow: hidden !important;
|
||||
}
|
||||
|
||||
/* Dashboard tables → block layout, transparent */
|
||||
/* Dashboard tables → block layout, transparent, no stacking blur */
|
||||
table.dashboard {
|
||||
display: block !important;
|
||||
width: 100% !important;
|
||||
background: transparent !important;
|
||||
border: none !important;
|
||||
box-shadow: none !important;
|
||||
backdrop-filter: none !important;
|
||||
-webkit-backdrop-filter: none !important;
|
||||
}
|
||||
|
||||
table.dashboard > tbody:not(.sortable),
|
||||
table.dashboard > thead:not(.stopgap) {
|
||||
backdrop-filter: none !important;
|
||||
-webkit-backdrop-filter: none !important;
|
||||
}
|
||||
|
||||
/* Hide colgroup (not needed with block layout) */
|
||||
@@ -960,7 +975,7 @@ table.dashboard > tbody.sortable {
|
||||
border-radius: var(--glass-radius) !important;
|
||||
box-shadow: var(--glass-shadow) !important;
|
||||
margin-bottom: 20px !important;
|
||||
padding-bottom: 8px !important;
|
||||
padding-bottom: 14px !important;
|
||||
overflow: hidden !important;
|
||||
position: relative;
|
||||
transition: background 0.3s ease, border-color 0.3s ease, box-shadow 0.3s ease !important;
|
||||
@@ -1018,14 +1033,32 @@ table.dashboard > tbody.sortable > tr:first-child {
|
||||
|
||||
/* Tile header text */
|
||||
span.tile-header,
|
||||
span.tile-header-left,
|
||||
span.tile-header-right {
|
||||
span.tile-header-left {
|
||||
color: var(--glass-text-heading) !important;
|
||||
font-weight: 600 !important;
|
||||
letter-spacing: 0.3px !important;
|
||||
font-size: 1em !important;
|
||||
}
|
||||
|
||||
/* Card header control icons — transparent, white icons */
|
||||
span.tile-header-right {
|
||||
color: rgba(255, 255, 255, 0.55) !important;
|
||||
font-size: 0.85em !important;
|
||||
}
|
||||
|
||||
span.tile-header-right i,
|
||||
span.tile-header-right .fa {
|
||||
background: transparent !important;
|
||||
border: none !important;
|
||||
color: rgba(255, 255, 255, 0.55) !important;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
span.tile-header-right i:hover,
|
||||
span.tile-header-right .fa:hover {
|
||||
color: rgba(255, 255, 255, 0.85) !important;
|
||||
}
|
||||
|
||||
/* Tile header layout */
|
||||
span.tile-header {
|
||||
display: flex !important;
|
||||
@@ -1051,7 +1084,8 @@ table.dashboard .usage-disk,
|
||||
table.dashboard .usage-bar {
|
||||
background: rgba(255, 255, 255, 0.08) !important;
|
||||
border-radius: 8px !important;
|
||||
height: 6px !important;
|
||||
height: 8px !important;
|
||||
margin: 6px 0 !important;
|
||||
overflow: hidden !important;
|
||||
}
|
||||
|
||||
@@ -1062,6 +1096,34 @@ table.dashboard .usage-bar > span {
|
||||
height: 100% !important;
|
||||
}
|
||||
|
||||
/* CPU bars — thin color-coded bars (higher specificity) */
|
||||
#displaybox table.dashboard .usage-disk {
|
||||
height: 10px !important;
|
||||
border-radius: 5px !important;
|
||||
}
|
||||
|
||||
#displaybox table.dashboard .usage-disk > span {
|
||||
border-radius: 5px !important;
|
||||
}
|
||||
|
||||
#displaybox table.dashboard .usage-disk.greenbar > span {
|
||||
background: linear-gradient(90deg, #22c55e, #4ade80) !important;
|
||||
}
|
||||
|
||||
#displaybox table.dashboard .usage-disk.orangebar > span {
|
||||
background: linear-gradient(90deg, #f97316, #fb923c) !important;
|
||||
}
|
||||
|
||||
#displaybox table.dashboard .usage-disk.redbar > span {
|
||||
background: linear-gradient(90deg, #ef4444, #f87171) !important;
|
||||
}
|
||||
|
||||
/* Hide empty pill label text inside CPU bars */
|
||||
#displaybox table.dashboard .usage-disk > span {
|
||||
font-size: 0 !important;
|
||||
color: transparent !important;
|
||||
}
|
||||
|
||||
/* Docker container icons in dashboard */
|
||||
table.dashboard img {
|
||||
border-radius: 6px !important;
|
||||
@@ -1118,6 +1180,88 @@ table.dashboard td a:hover {
|
||||
color: var(--glass-accent-hover) !important;
|
||||
}
|
||||
|
||||
/* Docker link — add appname links to accent color */
|
||||
table.dashboard span.appname a {
|
||||
color: var(--glass-accent) !important;
|
||||
}
|
||||
|
||||
table.dashboard span.appname a:hover {
|
||||
color: var(--glass-accent-hover) !important;
|
||||
}
|
||||
|
||||
/* Docker text — force white in dashboard (FolderView sets blue) */
|
||||
#docker_view span,
|
||||
#docker_view .inner span {
|
||||
color: var(--glass-text) !important;
|
||||
}
|
||||
|
||||
#docker_view a {
|
||||
color: var(--glass-accent) !important;
|
||||
}
|
||||
|
||||
/* CPU chart canvas — invert for dark background */
|
||||
#cpuchart {
|
||||
filter: invert(1) hue-rotate(180deg) !important;
|
||||
}
|
||||
|
||||
#cpu_chart td {
|
||||
width: 100% !important;
|
||||
}
|
||||
|
||||
#cpu_chart canvas {
|
||||
width: 100% !important;
|
||||
}
|
||||
|
||||
/* System donut charts — thinner ring with opaque center */
|
||||
div.pie::after {
|
||||
content: '' !important;
|
||||
position: absolute !important;
|
||||
top: 50% !important;
|
||||
left: 50% !important;
|
||||
transform: translate(-50%, -50%) !important;
|
||||
width: 78% !important;
|
||||
height: 78% !important;
|
||||
border-radius: 50% !important;
|
||||
background: rgba(20, 20, 30, 0.85) !important;
|
||||
}
|
||||
|
||||
div.pie {
|
||||
position: relative !important;
|
||||
}
|
||||
|
||||
/* Ensure labels are above donut hole */
|
||||
div.pie span,
|
||||
div.pie div {
|
||||
position: relative !important;
|
||||
z-index: 1 !important;
|
||||
}
|
||||
|
||||
/* Toggle switch — glass style */
|
||||
.switch-button-background {
|
||||
width: 40px !important;
|
||||
height: 22px !important;
|
||||
border-radius: 12px !important;
|
||||
background: rgba(255, 255, 255, 0.12) !important;
|
||||
border: 1px solid rgba(255, 255, 255, 0.15) !important;
|
||||
position: relative !important;
|
||||
cursor: pointer !important;
|
||||
transition: background 0.25s ease, border-color 0.25s ease !important;
|
||||
}
|
||||
|
||||
.switch-button-background.checked {
|
||||
background: var(--glass-accent) !important;
|
||||
border-color: var(--glass-accent) !important;
|
||||
}
|
||||
|
||||
.switch-button-button {
|
||||
width: 18px !important;
|
||||
height: 18px !important;
|
||||
border-radius: 50% !important;
|
||||
background: #fff !important;
|
||||
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.3) !important;
|
||||
transition: transform 0.25s ease !important;
|
||||
}
|
||||
|
||||
|
||||
/* ============================================
|
||||
INNER PAGES — Content Glass Wrapper
|
||||
@@ -1623,11 +1767,6 @@ div.clone-settings {
|
||||
background: transparent !important;
|
||||
}
|
||||
|
||||
/* Checkbox / switch styling */
|
||||
.switch-button-background {
|
||||
border-radius: 12px !important;
|
||||
}
|
||||
|
||||
/* Selection color */
|
||||
::selection {
|
||||
background: rgba(126, 184, 218, 0.3);
|
||||
|
||||
Reference in New Issue
Block a user