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);