diff --git a/assets/icons/openzfs-light.svg b/assets/icons/openzfs-light.svg new file mode 100644 index 0000000..9b2dacf --- /dev/null +++ b/assets/icons/openzfs-light.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/sidebar.js b/sidebar.js index 8303bbf..43e32bd 100644 --- a/sidebar.js +++ b/sidebar.js @@ -324,7 +324,10 @@ var replaceTimer = null; function debouncedReplace() { if (replaceTimer) clearTimeout(replaceTimer); - replaceTimer = setTimeout(replaceIcons, 200); + replaceTimer = setTimeout(function() { + replaceIcons(); + replacePluginIcons(); + }, 200); } // Watch for DOM changes (AJAX loads, FolderView manipulation) @@ -343,14 +346,48 @@ observer.observe(target, { childList: true, subtree: true }); } - // Replace Tailscale sidebar icon with light SVG - function replaceTailscaleIcon() { - var imgs = document.querySelectorAll('img[alt="Tailscale"]'); + // Plugin icon source → selfh.st light SVG replacement + // Maps partial src paths to icon names in /custom/assets/icons/ + var PLUGIN_ICON_MAP = { + '/plugins/tailscale/': 'tailscale', + '/plugins/zfs.master/': 'openzfs', + // SNMP has no selfh.st icon — leave for CSS invert filter + }; + + // Replace plugin icons on Settings/Plugins/Tools pages with selfh.st light SVGs. + // Also replaces Tailscale sidebar icon (img[alt="Tailscale"]). + function replacePluginIcons() { + // Settings/Tools/Plugins grid icons + var imgs = document.querySelectorAll('#displaybox img, 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'); + // Skip container icons (handled by replaceIcons) + if (img.classList.contains('img')) return; + // Skip sidebar logo + if (img.id === 'sidebar-logo') return; + // Skip already replaced + if (img.getAttribute('data-glass-icon')) return; + + var src = img.getAttribute('src') || ''; + var keys = Object.keys(PLUGIN_ICON_MAP); + for (var i = 0; i < keys.length; i++) { + if (src.indexOf(keys[i]) !== -1) { + var iconName = PLUGIN_ICON_MAP[keys[i]]; + var url = CDN_SVG + '/' + iconName + '-light.svg'; + img.src = url; + img.setAttribute('data-glass-icon', iconName); + img.removeAttribute('onerror'); + return; + } + } + + // Also handle Tailscale by alt attribute (sidebar) + if (img.alt === 'Tailscale') { + var tsUrl = CDN_SVG + '/tailscale-light.svg'; + if (src !== tsUrl) { + img.src = tsUrl; + img.setAttribute('data-glass-icon', 'tailscale'); + img.removeAttribute('onerror'); + } } }); } @@ -359,10 +396,10 @@ function initIcons() { // Initial replacement setTimeout(replaceIcons, 500); - setTimeout(replaceTailscaleIcon, 500); + setTimeout(replacePluginIcons, 500); // Second pass after FolderView finishes its DOM work setTimeout(replaceIcons, 2000); - setTimeout(replaceTailscaleIcon, 2000); + setTimeout(replacePluginIcons, 2000); // Start watching for future changes startObserver(); } diff --git a/style.css b/style.css index ae53350..325abde 100644 --- a/style.css +++ b/style.css @@ -1013,6 +1013,12 @@ table.dashboard > tbody.sortable > tr:last-child { border-bottom: none !important; } +/* Hide compact Load: row in Processor card — Overall Load row shows same info. + Unraid's DashStats.css hides span.switch but the row keeps 33px of padding/gap */ +table.dashboard > tbody.sortable > tr:has(.head_bar) { + display: none !important; +} + /* Dashboard card cells NOTE: display must NOT use !important so Unraid's jQuery .hide() can override */ table.dashboard > tbody.sortable > tr > td { @@ -1199,8 +1205,14 @@ table.dashboard span.appname a:hover { color: var(--glass-accent) !important; } -/* CPU chart canvas — invert for dark background */ +/* CPU chart — force block display (inline style sets table-row, breaking layout) */ +#cpu_chart { + display: block !important; +} + +/* CPU chart canvas — invert for dark background, block to prevent inline offset */ #cpuchart { + display: block !important; filter: invert(1) hue-rotate(180deg) !important; } @@ -1254,12 +1266,20 @@ div.pie div { } .switch-button-button { + position: absolute !important; + top: 50% !important; + left: 2px !important; + transform: translateY(-50%) !important; 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; + transition: left 0.25s ease, transform 0.25s ease !important; +} + +.switch-button-background.checked .switch-button-button { + left: calc(100% - 20px) !important; } @@ -2151,3 +2171,324 @@ img.popupIcon { .ca_credit { color: var(--glass-text-muted) !important; } + + +/* ============================================ + BUG FIXES — Phase 2: Text & Label Visibility + ============================================ */ + +/* Fix: Unraid tables use in , not . + Our existing rules only target thead th — add thead td. */ +#displaybox table:not(.dashboard) thead td { + color: var(--glass-text-muted) !important; + font-weight: 500 !important; + text-transform: uppercase !important; + font-size: 0.72em !important; + letter-spacing: 0.6px !important; + border-bottom: 1px solid rgba(255, 255, 255, 0.06) !important; + padding: 12px 16px !important; + background: transparent !important; +} + +/* Also cover generic thead td (non-#displaybox context) */ +table thead td { + color: var(--glass-text-muted) !important; + font-weight: 500 !important; +} + +/* Plugins page: table header row has opaque dark bg from tablesorter. + The grid role table uses which is fine, but ensure plugin + description text, author, version are clearly visible. */ +#displaybox table.tablesorter tbody td, +#displaybox table.tablesorter tbody th, +#displaybox .plugin_list td, +#displaybox table[role="grid"] td, +#displaybox table[role="grid"] [role="gridcell"] { + color: var(--glass-text) !important; +} + +/* Plugin name (h4/strong) and description (p) */ +#displaybox table.tablesorter h4, +#displaybox table.tablesorter strong, +#displaybox table[role="grid"] h4, +#displaybox table[role="grid"] strong { + color: var(--glass-text-heading) !important; +} + +#displaybox table.tablesorter p, +#displaybox table[role="grid"] p { + color: var(--glass-text-muted) !important; +} + +/* Plugin status text */ +#displaybox table.tablesorter .up-to-date, +#displaybox table[role="grid"] .up-to-date { + color: #4ade80 !important; +} + +/* Settings/Tools/Plugins icon grid labels (.PanelText) — + currently inherits accent blue from . Make labels white for readability. */ +.PanelText { + color: var(--glass-text) !important; +} + +/* Settings/Tools section headers (injected by Unraid as spans with inline styles) */ +#displaybox .content > span[style], +#displaybox .content span[style*="font-size"] { + color: var(--glass-text-heading) !important; +} + + +/* ============================================ + BUG FIXES — Phase 3: Icon Coloring + ============================================ */ + +/* Settings/Plugins/Tools icon grid: non-FA icons are PNG/SVG . + Plugin icons that have selfh.st light SVG replacements get swapped via JS + (sidebar.js replacePluginIcons). For others, apply invert filter. + We scope this to only target icons inside the icon-grid span (not the + whole page) and exclude icons already replaced by JS (data-glass-icon). */ +#displaybox .icon-setting img:not([data-glass-icon]), +#displaybox .page-setting img:not([data-glass-icon]), +#displaybox .icon-app img:not([data-glass-icon]), +#displaybox a[href*="/Settings/"] > span:first-child img:not([data-glass-icon]), +#displaybox a[href*="/Tools/"] > span:first-child img:not([data-glass-icon]), +#displaybox table[role="grid"] td:first-child img:not([data-glass-icon]) { + filter: brightness(0) invert(1) !important; + opacity: 0.85 !important; +} + +/* Plugin list: first-cell icons (some are not FA) */ +#displaybox table.tablesorter td:first-child img:not([data-glass-icon]), +#displaybox table[role="grid"] [role="gridcell"]:first-child img:not([data-glass-icon]) { + filter: brightness(0) invert(1) !important; + opacity: 0.85 !important; +} + + +/* ============================================ + BUG FIXES — Phase 4: Shadow & Rounding + ============================================ */ + +/* Soften box-shadow on inner page tables */ +#displaybox table:not(.dashboard) { + box-shadow: 0 4px 16px rgba(0, 0, 0, 0.15), inset 0 1px 0 rgba(255, 255, 255, 0.08) !important; +} + +/* Array Operation page: stacked form sections — + first/middle/last rounding for unified container look. + Unraid uses div.Panel for each section on Array Op. */ +#displaybox div.Panel + div.Panel { + margin-top: -1px !important; + border-top: 1px solid rgba(255, 255, 255, 0.06) !important; +} + +#displaybox div.Panel:not(:first-of-type):not(:last-of-type) { + border-radius: 0 !important; +} + +#displaybox div.Panel:not(:first-of-type):not(:last-of-type)::before { + display: none !important; +} + +#displaybox div.Panel + div.Panel:last-of-type { + border-radius: 0 0 var(--glass-radius) var(--glass-radius) !important; +} + +#displaybox div.Panel:first-of-type:has(+ div.Panel) { + border-radius: var(--glass-radius) var(--glass-radius) 0 0 !important; + margin-bottom: 0 !important; +} + + +/* ============================================ + BUG FIXES — Phase 5: Table & Form Styling + ============================================ */ + +/* Shares Browse page: file browser table uses a darker style. + Target the browse page specifically via URL-based class or #dir_list */ +#dir_list, +table.file_browser, +#displaybox table.browse_table, +#displaybox div[id*="browse"] table { + background: rgba(255, 255, 255, 0.06) !important; + border: 1px solid var(--glass-border) !important; + border-radius: var(--glass-radius) !important; +} + +#dir_list thead td, +#dir_list thead th, +table.file_browser thead td, +table.file_browser thead th { + background: rgba(255, 255, 255, 0.04) !important; + color: var(--glass-text-muted) !important; +} + +#dir_list tbody tr:nth-child(even), +table.file_browser tbody tr:nth-child(even) { + background: rgba(255, 255, 255, 0.03) !important; +} + +#dir_list tbody tr:hover, +table.file_browser tbody tr:hover { + background: rgba(255, 255, 255, 0.05) !important; +} + +/* Share Settings form page: wrap form content in glass styling. + The form uses dl/dt/dd inside a content div. */ +#displaybox .content > form, +#displaybox form[method], +#displaybox div.clone-settings, +#displaybox > .content > table:not(.dashboard):not(.tablesorter):not(.disk_status):not(.share_status) { + background: rgba(255, 255, 255, 0.06) !important; + backdrop-filter: blur(30px) saturate(1.3) !important; + -webkit-backdrop-filter: blur(30px) saturate(1.3) !important; + border: 1px solid var(--glass-border) !important; + border-radius: var(--glass-radius) !important; + padding: 16px !important; + margin-bottom: 16px !important; +} + +/* Apps detail panel: ensure tags/buttons area has glass bg */ +#alternateView .ca_template, +#alternateView table { + background: transparent !important; + border: none !important; + box-shadow: none !important; +} + + +/* ============================================ + BUG FIXES — Phase 6: Bars & Button Visibility + ============================================ */ + +/* Main page usage bars: match dashboard style (thin, rounded, gradient) */ +#displaybox table:not(.dashboard) .usage-disk, +#displaybox table:not(.dashboard) .usage-bar { + height: 8px !important; + border-radius: 8px !important; + background: rgba(255, 255, 255, 0.08) !important; + overflow: hidden !important; + margin: 4px 0 !important; +} + +#displaybox table:not(.dashboard) .usage-disk > span, +#displaybox table:not(.dashboard) .usage-bar > span { + height: 100% !important; + border-radius: 8px !important; + background: linear-gradient(90deg, rgba(126, 184, 218, 0.5), var(--glass-accent)) !important; + font-size: 0 !important; +} + +/* Color-coded bars on Main page */ +#displaybox table:not(.dashboard) .usage-disk.greenbar > span { + background: linear-gradient(90deg, #22c55e, #4ade80) !important; +} + +#displaybox table:not(.dashboard) .usage-disk.orangebar > span { + background: linear-gradient(90deg, #f97316, #fb923c) !important; +} + +#displaybox table:not(.dashboard) .usage-disk.redbar > span { + background: linear-gradient(90deg, #ef4444, #f87171) !important; +} + +/* Plugins Update: ensure update arrow buttons are visible */ +#displaybox table.tablesorter input[type="button"], +#displaybox table[role="grid"] input[type="button"], +#displaybox table.tablesorter button:not([disabled]), +#displaybox table[role="grid"] button:not([disabled]) { + background: var(--glass-accent-subtle) !important; + color: var(--glass-accent) !important; + border: 1px solid rgba(126, 184, 218, 0.25) !important; +} + +/* VM action buttons — ensure visibility */ +#displaybox #vm_list button, +#displaybox #vm_list input[type="button"] { + background: var(--glass-accent-subtle) !important; + color: var(--glass-accent) !important; + border: 1px solid rgba(126, 184, 218, 0.25) !important; +} + + +/* ============================================ + BUG FIXES — Phase 7: Page-Specific Layouts + ============================================ */ + +/* Dashboard #3: header clipping — ensure UNRAID banner is fully visible */ +#header { + overflow: visible !important; + z-index: 100 !important; +} + +/* Ensure the Unraid logo/brand area doesn't clip */ +#header > div:first-child, +#header .brand, +#header a[href*="unraid.net"] { + overflow: visible !important; +} + +/* Docker #1: folder-preview wrapper has opaque glass bg. + Make it more subtle/transparent so container items + don't appear in a "tab-like" wrapper. */ +.folder-preview, +div[class*="folder-preview"] { + background: rgba(255, 255, 255, 0.03) !important; + border: 1px solid rgba(255, 255, 255, 0.06) !important; + border-radius: 10px !important; + backdrop-filter: none !important; + -webkit-backdrop-filter: none !important; +} + +/* Docker folder-storage cell — reduce the wrapper appearance */ +td.folder-storage { + background: transparent !important; + border: none !important; + padding: 4px 8px !important; +} + +/* Apps #1: ribbon/badge corner rounding. + Ensure the card clips the ribbon properly. */ +.ca_holder { + overflow: hidden !important; + border-radius: 16px !important; +} + +/* Badge text positioning — ensure visible */ +.ca_holder .installedCardBackground + span, +.ca_holder .betaCardBackground + span, +.ca_holder .officialCardBackground + span, +.ca_holder .warningCardBackground + span, +.ca_holder .greenCardBackground + span { + color: #fff !important; + font-size: 10px !important; + z-index: 2 !important; +} + +/* ZFS Master: toggle icon gap fix. + The toggle/refresh area sits in a div that has excess margin. + Tighten the layout. */ +#displaybox [id*="zfs"] .switch-button-background, +#displaybox [id*="ZFS"] .switch-button-background { + display: inline-block !important; + vertical-align: middle !important; + margin: 0 8px !important; +} + +/* Fix stacked panels: don't apply to tabpanel children + which have their own panel structure */ +[role="tabpanel"] div.Panel + div.Panel { + margin-top: 16px !important; + border-top: 1px solid var(--glass-border) !important; + border-radius: var(--glass-radius) !important; +} + +[role="tabpanel"] div.Panel:not(:first-of-type):not(:last-of-type) { + border-radius: var(--glass-radius) !important; +} + +[role="tabpanel"] div.Panel:first-of-type:has(+ div.Panel) { + border-radius: var(--glass-radius) !important; + margin-bottom: 16px !important; +}