Keep glyph notification hints compact

This commit is contained in:
David Heinemeier Hansson
2026-05-27 14:09:26 +02:00
parent a09cfc3460
commit e490f743db
3 changed files with 20 additions and 3 deletions
@@ -53,6 +53,10 @@ function glyphFromHints(hints) {
return "" return ""
} }
function shouldRenderCompactGlyph(glyph, iconSource) {
return String(glyph || "").length > 0 && String(iconSource || "").length === 0
}
function snapshotOf(notification, timestamp) { function snapshotOf(notification, timestamp) {
var n = notification || {} var n = notification || {}
var id = n.id || 0 var id = n.id || 0
@@ -178,6 +182,7 @@ if (typeof module !== "undefined") {
shouldBypassDnd: shouldBypassDnd, shouldBypassDnd: shouldBypassDnd,
isEphemeralApp: isEphemeralApp, isEphemeralApp: isEphemeralApp,
glyphFromHints: glyphFromHints, glyphFromHints: glyphFromHints,
shouldRenderCompactGlyph: shouldRenderCompactGlyph,
snapshotOf: snapshotOf, snapshotOf: snapshotOf,
historyEntry: historyEntry, historyEntry: historyEntry,
dedupeByOriginalId: dedupeByOriginalId, dedupeByOriginalId: dedupeByOriginalId,
@@ -37,7 +37,8 @@ Rectangle {
// The `check` flag avoids Qt's missing-texture placeholder for unknown names. // The `check` flag avoids Qt's missing-texture placeholder for unknown names.
readonly property string smallIconSource: image.length > 0 ? image : iconSource(appIcon) readonly property string smallIconSource: image.length > 0 ? image : iconSource(appIcon)
readonly property bool hasGlyph: glyph.length > 0 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 summaryStartsWithGlyph: NotificationLogic.summaryStartsWithGlyph(summary)
readonly property bool singleLineToast: sanitizedBody.length === 0 readonly property bool singleLineToast: sanitizedBody.length === 0
readonly property bool collapseRedundantIcon: singleLineToast && !hasGlyph && summaryStartsWithGlyph readonly property bool collapseRedundantIcon: singleLineToast && !hasGlyph && summaryStartsWithGlyph
@@ -97,7 +98,7 @@ Rectangle {
Layout.rightMargin: Style.space(12) Layout.rightMargin: Style.space(12)
Layout.topMargin: root.singleLineToast ? Style.space(7) : Style.space(10) Layout.topMargin: root.singleLineToast ? Style.space(7) : Style.space(10)
Layout.bottomMargin: 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 { Item {
id: smallIconSlot id: smallIconSlot
@@ -107,7 +108,7 @@ Rectangle {
// Hide the slot when the icon failed to resolve (themed-icon name // 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 // not in the user's icon theme) AND we don't have a glyph fallback
// — prevents rendering Qt's pink broken-image placeholder. // — 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 { Image {
id: smallIconImage 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 { ColumnLayout {
Layout.fillWidth: true Layout.fillWidth: true
Layout.alignment: Qt.AlignVCenter Layout.alignment: Qt.AlignVCenter
+2
View File
@@ -37,6 +37,8 @@ assertEqual(
assert(notifications.summaryStartsWithGlyph('󰂚 Silenced'), 'notifications detect glyph-prefixed summaries') assert(notifications.summaryStartsWithGlyph('󰂚 Silenced'), 'notifications detect glyph-prefixed summaries')
assert(!notifications.summaryStartsWithGlyph('Normal summary'), 'notifications ignore normal summaries as glyph-prefixed') 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: 'omarchy-action', urgency: 1 }, 2), 'omarchy action toasts bypass DND')
assert(notifications.shouldBypassDnd({ appName: 'notify-send', urgency: 2 }, 2), 'critical notify-send bypasses DND') assert(notifications.shouldBypassDnd({ appName: 'notify-send', urgency: 2 }, 2), 'critical notify-send bypasses DND')