From e490f743dba798642703b9d3e558959ee7b3457a Mon Sep 17 00:00:00 2001 From: David Heinemeier Hansson Date: Wed, 27 May 2026 14:09:26 +0200 Subject: [PATCH] Keep glyph notification hints compact --- shell/plugins/notifications/NotificationLogic.js | 5 +++++ .../components/NotificationCard.qml | 16 +++++++++++++--- test/shell.d/notifications-test.sh | 2 ++ 3 files changed, 20 insertions(+), 3 deletions(-) diff --git a/shell/plugins/notifications/NotificationLogic.js b/shell/plugins/notifications/NotificationLogic.js index d06e6b26..53def626 100644 --- a/shell/plugins/notifications/NotificationLogic.js +++ b/shell/plugins/notifications/NotificationLogic.js @@ -53,6 +53,10 @@ function glyphFromHints(hints) { return "" } +function shouldRenderCompactGlyph(glyph, iconSource) { + return String(glyph || "").length > 0 && String(iconSource || "").length === 0 +} + function snapshotOf(notification, timestamp) { var n = notification || {} var id = n.id || 0 @@ -178,6 +182,7 @@ if (typeof module !== "undefined") { shouldBypassDnd: shouldBypassDnd, isEphemeralApp: isEphemeralApp, glyphFromHints: glyphFromHints, + shouldRenderCompactGlyph: shouldRenderCompactGlyph, snapshotOf: snapshotOf, historyEntry: historyEntry, dedupeByOriginalId: dedupeByOriginalId, diff --git a/shell/plugins/notifications/components/NotificationCard.qml b/shell/plugins/notifications/components/NotificationCard.qml index e0eace43..f560d581 100644 --- a/shell/plugins/notifications/components/NotificationCard.qml +++ b/shell/plugins/notifications/components/NotificationCard.qml @@ -37,7 +37,8 @@ Rectangle { // The `check` flag avoids Qt's missing-texture placeholder for unknown names. readonly property string smallIconSource: image.length > 0 ? image : iconSource(appIcon) readonly property bool hasGlyph: glyph.length > 0 - readonly property bool hasSmallIcon: smallIconSource.length > 0 || hasGlyph + readonly property bool compactGlyph: NotificationLogic.shouldRenderCompactGlyph(glyph, smallIconSource) + readonly property bool hasSmallIcon: smallIconSource.length > 0 readonly property bool summaryStartsWithGlyph: NotificationLogic.summaryStartsWithGlyph(summary) readonly property bool singleLineToast: sanitizedBody.length === 0 readonly property bool collapseRedundantIcon: singleLineToast && !hasGlyph && summaryStartsWithGlyph @@ -97,7 +98,7 @@ Rectangle { Layout.rightMargin: Style.space(12) Layout.topMargin: root.singleLineToast ? Style.space(7) : Style.space(10) Layout.bottomMargin: root.singleLineToast ? Style.space(7) : Style.space(10) - spacing: root.collapseRedundantIcon ? 0 : Style.space(12) + spacing: root.collapseRedundantIcon ? 0 : (root.compactGlyph ? Style.space(8) : Style.space(12)) Item { id: smallIconSlot @@ -107,7 +108,7 @@ Rectangle { // Hide the slot when the icon failed to resolve (themed-icon name // not in the user's icon theme) AND we don't have a glyph fallback // — prevents rendering Qt's pink broken-image placeholder. - visible: !root.collapseRedundantIcon && root.hasSmallIcon && (root.hasGlyph || smallIconImage.status !== Image.Error) + visible: !root.collapseRedundantIcon && !root.compactGlyph && root.hasSmallIcon && (root.hasGlyph || smallIconImage.status !== Image.Error) Image { id: smallIconImage @@ -133,6 +134,15 @@ Rectangle { } } + Text { + Layout.alignment: Qt.AlignVCenter + visible: root.compactGlyph + text: root.glyph + color: Color.notifications.text + font.family: root.fontFamily + font.pixelSize: Style.font.icon + } + ColumnLayout { Layout.fillWidth: true Layout.alignment: Qt.AlignVCenter diff --git a/test/shell.d/notifications-test.sh b/test/shell.d/notifications-test.sh index 141fce0e..eb5d23d5 100644 --- a/test/shell.d/notifications-test.sh +++ b/test/shell.d/notifications-test.sh @@ -37,6 +37,8 @@ assertEqual( assert(notifications.summaryStartsWithGlyph('󰂚 Silenced'), 'notifications detect glyph-prefixed summaries') assert(!notifications.summaryStartsWithGlyph('Normal summary'), 'notifications ignore normal summaries as glyph-prefixed') +assert(notifications.shouldRenderCompactGlyph('K', ''), 'notifications render glyph-only hints compactly') +assert(!notifications.shouldRenderCompactGlyph('K', 'file:///tmp/image.png'), 'notifications keep image-backed glyph hints in the icon slot') assert(notifications.shouldBypassDnd({ appName: 'omarchy-action', urgency: 1 }, 2), 'omarchy action toasts bypass DND') assert(notifications.shouldBypassDnd({ appName: 'notify-send', urgency: 2 }, 2), 'critical notify-send bypasses DND')