From 30ccaf51a8720ca101d8cdb15500d5fd120baa62 Mon Sep 17 00:00:00 2001
From: Psychotoxical <171614930+Psychotoxical@users.noreply.github.com>
Date: Sun, 21 Jun 2026 00:48:26 +0200
Subject: [PATCH] fix(updater): rebuild the update modal on a reusable Modal
(#1142)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
* feat(ui): add reusable Modal component
Portal + dimmed backdrop (no backdrop-filter — on WebKitGTK the blur bleeds
onto modal content on some GPU stacks), Escape/backdrop/X to close, header
(icon/title/subtitle) + scrollable body + footer slot. First consumer is the
update modal; the other hand-rolled modals migrate onto it over time.
* fix(updater): rebuild the update modal on the reusable Modal
Fixes a user report (Manjaro / AMD / X11): blurry modal text (the eq-popup
backdrop-filter bled onto the content), the version arrow sitting between the
two header rows, and the unclear Skip / Remind buttons. Now uses the no-blur
Modal shell; the header icon aligns with the title; Skip is a clear button and
Remind me later is the accent action when there is no in-app install. Drops the
now-dead update-modal shell CSS.
* docs(changelog): update notification popup fix (PR #1142)
---
CHANGELOG.md | 6 +
src/components/AppUpdater.tsx | 409 ++++++++++++++---------------
src/components/Modal.tsx | 78 ++++++
src/styles/components/index.css | 1 +
src/styles/components/ui-modal.css | 98 +++++++
src/styles/layout/update-toast.css | 53 +---
6 files changed, 382 insertions(+), 263 deletions(-)
create mode 100644 src/components/Modal.tsx
create mode 100644 src/styles/components/ui-modal.css
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 4f65b134..0c7188ea 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -146,6 +146,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
* Track-advance queue pushes no longer suspend idle auto-pull, so the connection LED does not flash yellow on every song change. Yellow sync still appears after a local queue edit while paused; it clears while audio is playing.
+### Update notification — clearer popup on Linux
+
+**By [@Psychotoxical](https://github.com/Psychotoxical), PR [#1142](https://github.com/Psychotoxical/psysonic/pull/1142)**, reported by zunoz on Discord
+
+* The "new version available" popup no longer shows blurry, unfocused text on some Linux setups (the background blur could bleed onto the dialog). The version arrow now lines up with the heading, and the Skip / Remind me later buttons read clearly — Remind me later is the highlighted action when there's no in-app installer.
+
## [1.48.1] - 2026-06-15
diff --git a/src/components/AppUpdater.tsx b/src/components/AppUpdater.tsx
index 30383772..42e3ec5d 100644
--- a/src/components/AppUpdater.tsx
+++ b/src/components/AppUpdater.tsx
@@ -1,10 +1,11 @@
-import { createPortal } from 'react-dom';
+import { type ReactNode } from 'react';
import { open } from '@tauri-apps/plugin-shell';
-import { ArrowUpCircle, CheckCircle2, ChevronDown, Download, FolderOpen, RefreshCw, ShieldCheck, X } from 'lucide-react';
+import { ArrowUpCircle, CheckCircle2, ChevronDown, Download, FolderOpen, RefreshCw, ShieldCheck } from 'lucide-react';
import { useTranslation } from 'react-i18next';
import { version as currentVersion } from '../../package.json';
import { formatBytes } from '../utils/format/formatBytes';
import { useAppUpdater } from '../hooks/useAppUpdater';
+import Modal from './Modal';
import Changelog from './appUpdater/Changelog';
export default function AppUpdater() {
@@ -18,222 +19,208 @@ export default function AppUpdater() {
if (!release || dismissed) return null;
- return createPortal(
- <>
-
- {t('common.updaterMacReadyTitle', { defaultValue: 'Ready to install' })}
-
-
- {t('common.updaterMacReady', {
- defaultValue: 'The update downloads, verifies and applies in place — no DMG needed. The app restarts automatically when done.',
- })}
-
+ {t('common.updaterMacReadyTitle', { defaultValue: 'Ready to install' })}
+
+
+ {t('common.updaterMacReady', {
+ defaultValue: 'The update downloads, verifies and applies in place — no DMG needed. The app restarts automatically when done.',
+ })}
+