diff --git a/containers/libreportal/frontend/core/setup/css/setup-wizard.css b/containers/libreportal/frontend/core/setup/css/setup-wizard.css index b770ed9..3911eda 100755 --- a/containers/libreportal/frontend/core/setup/css/setup-wizard.css +++ b/containers/libreportal/frontend/core/setup/css/setup-wizard.css @@ -1322,3 +1322,25 @@ body.setup-wizard-open .eo-modal { z-index: 10000; } color: #86ecb6; border: 1px solid rgba(90, 220, 150, 0.45); } + +/* Capacity meter on a drive card. Inline and small on purpose: it encodes the + proportion the text deliberately doesn't repeat, without adding a row. + Filled = free space, so the bar drains as the disk fills. */ +.setup-storage-meter { + display: inline-block; + vertical-align: middle; + width: 64px; + height: 5px; + margin-left: 10px; + border-radius: 3px; + background: rgba(255, 255, 255, 0.20); + overflow: hidden; +} +.setup-storage-meter > span { + display: block; + height: 100%; + border-radius: 3px; + background: rgba(160, 226, 255, 0.85); +} +.setup-storage-meter-mid > span { background: rgba(255, 206, 110, 0.9); } +.setup-storage-meter-high > span { background: rgba(255, 138, 138, 0.95); } diff --git a/containers/libreportal/frontend/core/setup/js/setup-wizard.js b/containers/libreportal/frontend/core/setup/js/setup-wizard.js index 298f812..8ec6cbb 100755 --- a/containers/libreportal/frontend/core/setup/js/setup-wizard.js +++ b/containers/libreportal/frontend/core/setup/js/setup-wizard.js @@ -448,6 +448,29 @@ class SetupWizard { return map[c.id] || c.message; } + // A thin capacity bar rather than a second number. + // + // Which figure matters depends on the question. For "will my data fit?" — + // the question this step actually asks — absolute free space decides it: a + // 4 GB disk that is 89% free is still useless for a media library. + // Percentage answers "is this filling up?", a health signal rather than a + // placement one. So the text carries the magnitude and the bar the + // proportion, which is what the eye reads fastest. + // + // The bar fills with FREE space, not used. Filling by usage meant a healthy + // 7%-full disk rendered as an almost-empty track that read as a broken + // widget, and it disagreed with the text right beside it. Filled = room to + // spare, draining = filling up, which is the same direction as the words. + _storageMeter(c) { + const used = Math.max(0, Math.min(100, Number(c.used_pct) || 0)); + const free = 100 - used; + const level = free <= 10 ? ' setup-storage-meter-high' + : (free <= 25 ? ' setup-storage-meter-mid' : ''); + return ``; + } + // One card, one line. // // The badge carries severity and Details carries the explanation, so the card @@ -472,7 +495,10 @@ class SetupWizard { ${this.escapeHtml(title)} ${badge} - ${this.escapeHtml(c.size)} · ${this.escapeHtml(c.free)} free · ${this.escapeHtml(c.fstype)}${c.removable ? ' · removable' : ''} + + ${this.escapeHtml(c.free)} free of ${this.escapeHtml(c.size)}${c.removable ? ' · removable' : ''} + ${this._storageMeter(c)} + `; diff --git a/scripts/webui/data/generators/system/webui_storage_candidates.sh b/scripts/webui/data/generators/system/webui_storage_candidates.sh index b49b81d..c9327f2 100644 --- a/scripts/webui/data/generators/system/webui_storage_candidates.sh +++ b/scripts/webui/data/generators/system/webui_storage_candidates.sh @@ -70,6 +70,8 @@ webuiGenerateStorageCandidates() system_json+=",\"free\":\"$(_lpJsonEsc "$sys_free")\"" system_json+=",\"uuid\":\"$(_lpJsonEsc "$sys_uuid")\"" system_json+=",\"options\":\"$(_lpJsonEsc "$sys_opts")\"" + local sys_pct; sys_pct=$(df -Pk "$sys_root" 2>/dev/null | awk 'NR==2 {gsub("%","",$5); print $5}') + system_json+=",\"used_pct\":${sys_pct:-0}" system_json+=",\"removable\":false" system_json+=",\"apps\":\"$(_lpJsonEsc "$(storageAppsOnRoot "$sys_root" 2>/dev/null | paste -sd, -)")\"" system_json+=",\"checks\":$sys_checks}" @@ -112,6 +114,8 @@ webuiGenerateStorageCandidates() candidates+=",\"free\":\"$(_lpJsonEsc "$avail")\"" candidates+=",\"uuid\":\"$(_lpJsonEsc "$uuid_val")\"" candidates+=",\"options\":\"$(_lpJsonEsc "$opts_val")\"" + local used_pct; used_pct=$(df -Pk "$target" 2>/dev/null | awk 'NR==2 {gsub("%","",$5); print $5}') + candidates+=",\"used_pct\":${used_pct:-0}" candidates+=",\"removable\":$([[ "$rm_flag" == "1" ]] && echo true || echo false)" candidates+=",\"verdict\":\"$verdict\"" candidates+=",\"fstab_line\":\"$(_lpJsonEsc "$fstab_line")\""