From d3c64753213e541242f2f7cd248cfb07887fe900 Mon Sep 17 00:00:00 2001
From: Sucukdeluxe <259325684+Sucukdeluxe@users.noreply.github.com>
Date: Fri, 21 Aug 2026 00:48:10 +0200
Subject: [PATCH] refine: align positive update presentation
Display the primary release heading as What's new?, render the install and active download states in the success palette, and reserve red exclusively for cancellation and failure.
---
renderer/app.js | 5 ++++-
renderer/index.html | 2 +-
renderer/styles.css | 6 ++++++
tests/ui-smoke.js | 6 ++++--
4 files changed, 15 insertions(+), 4 deletions(-)
diff --git a/renderer/app.js b/renderer/app.js
index 0af1ea0..445ae9b 100644
--- a/renderer/app.js
+++ b/renderer/app.js
@@ -7467,9 +7467,12 @@ function _renderUpdateReleaseNotes(container, value) {
: 'update-release-line';
const source = heading ? heading[2] : bullet ? `• ${bullet[1]}` : line;
const cleaned = _cleanUpdateReleaseText(source);
+ const displayText = className === 'update-release-heading' && cleaned.toLocaleLowerCase('en-US') === "what's new"
+ ? `${cleaned}?`
+ : cleaned;
const available = 2400 - consumed;
if (available <= 0) break;
- const text = cleaned.length > available ? `${cleaned.slice(0, Math.max(0, available - 1))}…` : cleaned;
+ const text = displayText.length > available ? `${displayText.slice(0, Math.max(0, available - 1))}…` : displayText;
const element = document.createElement('div');
element.className = className;
element.textContent = text;
diff --git a/renderer/index.html b/renderer/index.html
index 7636850..9cb4396 100644
--- a/renderer/index.html
+++ b/renderer/index.html
@@ -174,7 +174,7 @@
-
+
diff --git a/renderer/styles.css b/renderer/styles.css
index 377a857..7eb5686 100644
--- a/renderer/styles.css
+++ b/renderer/styles.css
@@ -2540,6 +2540,12 @@ select.hs-input { max-width: none; width: auto; min-width: 140px; }
transition: width .48s cubic-bezier(.22, 1, .36, 1), background-color .16s ease;
}
+.update-progress-track span[data-state="downloading"],
+.update-progress-track span[data-state="verifying"],
+.update-progress-track span[data-state="prepared"] {
+ background: var(--success);
+}
+
.update-progress-track span[data-state="aborted"],
.update-progress-track span[data-state="error"] {
background: var(--danger);
diff --git a/tests/ui-smoke.js b/tests/ui-smoke.js
index 0aaf4e7..d5fd702 100644
--- a/tests/ui-smoke.js
+++ b/tests/ui-smoke.js
@@ -2418,7 +2418,7 @@ setTimeout(async () => {
check('Minimum Accounts keeps auto-check reachable and content contained', minimumResponsiveContract.autoCheckVisible && minimumResponsiveContract.accountsMainFits);
check('Minimum Uploads preserves availability and telemetry information', minimumResponsiveContract.telemetryVisible && minimumResponsiveContract.availabilityVisible);
- const updateOverlayState = await wc.executeJavaScript('_knownUpdateInfo = { available: true, remoteVersion: "9.9.9" }; _syncHeaderUpdateState(); document.getElementById("headerUpdateBtn").focus(); showUpdateBanner({ remoteVersion: "9.9.9", releaseNotes: "\\\\n\\\\n\\\\n## New in this version\\\\n\\\\n\\\\n### Menus and navigation\\\\n\\\\n- Added live language switching.\\\\n- Improved settings layout.\\\\n\\\\n\\\\n" }); (() => { const overlay = document.getElementById("updateBanner"); const dialog = overlay?.querySelector(".update-dialog"); const button = document.getElementById("headerUpdateBtn"); return [overlay?.classList.contains("update-overlay"), overlay?.style.display, dialog?.getAttribute("role"), dialog?.getAttribute("aria-modal"), button?.hidden, getComputedStyle(button).display].join("|"); })()');
+ const updateOverlayState = await wc.executeJavaScript('_knownUpdateInfo = { available: true, remoteVersion: "9.9.9" }; _syncHeaderUpdateState(); document.getElementById("headerUpdateBtn").focus(); showUpdateBanner({ remoteVersion: "9.9.9", releaseNotes: "\\\\n\\\\n\\\\n## What\'s new\\\\n\\\\n\\\\n### Menus and navigation\\\\n\\\\n- Added live language switching.\\\\n- Improved settings layout.\\\\n\\\\n\\\\n" }); (() => { const overlay = document.getElementById("updateBanner"); const dialog = overlay?.querySelector(".update-dialog"); const button = document.getElementById("headerUpdateBtn"); return [overlay?.classList.contains("update-overlay"), overlay?.style.display, dialog?.getAttribute("role"), dialog?.getAttribute("aria-modal"), button?.hidden, getComputedStyle(button).display].join("|"); })()');
check('Available update opens an accessible update dialog', updateOverlayState === 'true|flex|dialog|true|false|flex');
await new Promise(resolve => setTimeout(resolve, 100));
@@ -2445,10 +2445,12 @@ setTimeout(async () => {
const updateDialogActions = await wc.executeJavaScript('[document.getElementById("dismissUpdateBtn")?.textContent?.trim(), document.getElementById("installUpdateBtn")?.textContent?.trim()].join("|")');
check('Update dialog offers cancel and install actions', updateDialogActions === 'Abbrechen|Jetzt installieren');
+ const updateInstallStyle = await wc.executeJavaScript('(() => { const button = document.getElementById("installUpdateBtn"); return [button.classList.contains("btn-success"), getComputedStyle(button).backgroundImage].join("|"); })()');
+ check('Update dialog renders its install action in green', updateInstallStyle.startsWith('true|linear-gradient'));
const updateCloseColor = await wc.executeJavaScript('getComputedStyle(document.getElementById("updateCloseBtn")).color');
check('Update dialog exposes a red close action', updateCloseColor === 'rgb(255, 133, 140)');
const updateDialogChangelog = await wc.executeJavaScript('(() => { const title = document.querySelector(".update-release-notes-title"); const body = document.getElementById("updateReleaseNotesBody"); const heading = body?.querySelector(".update-release-heading"); const category = body?.querySelector(".update-release-category"); const items = [...(body?.querySelectorAll(".update-release-item") || [])]; const titleRect = title?.getBoundingClientRect(); const bodyRect = body?.getBoundingClientRect(); return { hidden: document.getElementById("updateReleaseNotes")?.hidden, title: title?.textContent?.trim(), heading: heading?.textContent, headingSize: getComputedStyle(heading).fontSize, category: category?.textContent, categorySize: getComputedStyle(category).fontSize, items: items.map(item => item.textContent).join("|"), gap: bodyRect && titleRect ? bodyRect.top - titleRect.bottom : null }; })()');
- check('Update dialog renders a compact changelog with larger headings and categories', updateDialogChangelog.hidden === false && updateDialogChangelog.title === 'Changelog' && updateDialogChangelog.heading === 'New in this version' && updateDialogChangelog.headingSize === '14px' && updateDialogChangelog.category === 'Menus and navigation' && updateDialogChangelog.categorySize === '13px' && updateDialogChangelog.items === '• Added live language switching.|• Improved settings layout.' && updateDialogChangelog.gap <= 10);
+ check('Update dialog renders a compact changelog with larger headings and categories', updateDialogChangelog.hidden === false && updateDialogChangelog.title === 'Changelog' && updateDialogChangelog.heading === "What's new?" && updateDialogChangelog.headingSize === '14px' && updateDialogChangelog.category === 'Menus and navigation' && updateDialogChangelog.categorySize === '13px' && updateDialogChangelog.items === '• Added live language switching.|• Improved settings layout.' && updateDialogChangelog.gap <= 10);
const updateDialogSize = await wc.executeJavaScript('(() => ({ width: document.querySelector(".update-dialog")?.getBoundingClientRect().width, notesHeight: document.getElementById("updateReleaseNotes")?.getBoundingClientRect().height }))()');
check('Update dialog and changelog provide more horizontal and vertical room', updateDialogSize.width === 576 && updateDialogSize.notesHeight === 264);