feat: reveal available updates beside speed

Collapse the header update action completely when no update exists and animate the green action outward to the left of the fixed bandwidth widget only after a real update is detected.
This commit is contained in:
Sucukdeluxe
2026-08-21 00:12:17 +02:00
parent de64499c12
commit ccf60db15f
5 changed files with 68 additions and 17 deletions
+8 -1
View File
@@ -801,6 +801,7 @@ function _setHeaderUpdateLabel(text) {
function _syncHeaderUpdateState() {
const button = document.getElementById('headerUpdateBtn');
const slot = document.getElementById('headerUpdateSlot');
const available = !!(_knownUpdateInfo && _knownUpdateInfo.available);
const version = available ? String(_knownUpdateInfo.remoteVersion || '').replace(/^v/i, '') : '';
const hint = _updateCheckBusy
@@ -808,10 +809,15 @@ function _syncHeaderUpdateState() {
: available
? `Update v${version || 'unbekannt'} verfügbar. Klicken zum Installieren.`
: 'Nach Aktualisierungen suchen';
if (slot) {
slot.classList.toggle('is-visible', available);
slot.setAttribute('aria-hidden', available ? 'false' : 'true');
}
if (button) {
button.classList.toggle('update-available', available);
button.classList.toggle('is-checking', _updateCheckBusy);
button.disabled = _updateCheckBusy;
button.disabled = !available || _updateCheckBusy;
button.tabIndex = available ? 0 : -1;
button.setAttribute('aria-busy', _updateCheckBusy ? 'true' : 'false');
button.setAttribute('aria-label', hint);
button.title = hint;
@@ -843,6 +849,7 @@ async function requestUpdateCheck({ forceRefresh = true } = {}) {
} else if (result && result.error) {
showCopyToast('Updateprüfung fehlgeschlagen');
} else {
_knownUpdateInfo = null;
showCopyToast('Kein Update verfügbar');
}
return result;
+6 -4
View File
@@ -54,6 +54,12 @@
</div>
<div class="header-spacer" aria-hidden="true"></div>
<div class="header-cluster header-utilities">
<div class="header-update-slot" id="headerUpdateSlot" aria-hidden="true">
<button class="header-update-button" id="headerUpdateBtn" title="Nach Aktualisierungen suchen" aria-label="Nach Aktualisierungen suchen" data-tooltip="Nach Aktualisierungen suchen" tabindex="-1" disabled>
<svg class="header-action-icon" aria-hidden="true"><use href="#icon-download"></use></svg>
<span class="header-update-label">Update</span>
</button>
</div>
<div class="upload-speed-sparkline" id="uploadSpeedSparkline" title="Aktuelle Upload-Geschwindigkeit" aria-label="Aktuelle Upload-Geschwindigkeit">
<span class="upload-speed-chart" aria-hidden="true">
<span class="upload-speed-baseline"></span>
@@ -61,10 +67,6 @@
</span>
<strong id="uploadSpeedValue">0 B/s</strong>
</div>
<button class="header-update-button" id="headerUpdateBtn" title="Nach Aktualisierungen suchen" aria-label="Nach Aktualisierungen suchen" data-tooltip="Nach Aktualisierungen suchen">
<svg class="header-action-icon" aria-hidden="true"><use href="#icon-download"></use></svg>
<span class="header-update-label">Update</span>
</button>
<span class="header-divider" aria-hidden="true"></span>
<nav class="menu-bar" id="menuBar" aria-label="Anwendungsmenüs">
<div class="menu-bar-item" data-menu="datei">
+38 -1
View File
@@ -2109,6 +2109,29 @@ select.hs-input { max-width: none; width: auto; min-width: 140px; }
border: 0;
}
.header-update-slot {
width: 0;
flex: 0 0 0;
height: 32px;
margin-right: -4px;
overflow: hidden;
opacity: 0;
visibility: hidden;
pointer-events: none;
transition: width .28s cubic-bezier(.22, 1, .36, 1), flex-basis .28s cubic-bezier(.22, 1, .36, 1), margin-right .28s cubic-bezier(.22, 1, .36, 1), opacity .18s ease, visibility 0s linear .28s;
}
.header-update-slot.is-visible {
width: 146px;
flex-basis: 146px;
margin-right: 0;
overflow: visible;
opacity: 1;
visibility: visible;
pointer-events: auto;
transition-delay: 0s;
}
.header-update-button {
position: relative;
width: 146px;
@@ -2127,7 +2150,16 @@ select.hs-input { max-width: none; width: auto; min-width: 140px; }
font: inherit;
font-size: 12px;
font-weight: 700;
transition: background-color .14s, transform .14s;
opacity: 0;
transform: translateX(14px);
pointer-events: none;
transition: background-color .14s, transform .28s cubic-bezier(.22, 1, .36, 1), opacity .18s ease;
}
.header-update-slot.is-visible .header-update-button {
opacity: 1;
transform: translateX(0);
pointer-events: auto;
}
.header-update-button.update-available {
@@ -4040,6 +4072,11 @@ input[type="checkbox"] {
padding: 0;
}
.header-update-slot.is-visible {
width: 34px;
flex-basis: 34px;
}
.header-update-label,
.version-label {
display: none;