fix: notif action size + more spacing

Also shape morph for notif actions + icon close/copy
This commit is contained in:
2 * r + 2 * t 2026-05-05 22:07:04 +10:00
parent 4eca117ade
commit 53a0a7d977
2 changed files with 78 additions and 71 deletions

View file

@ -46,18 +46,22 @@ StyledRect {
property real shapeMorphExpansion: shapeMorph && pressed ? 24 : 0 // Apparently it's always 24px no matter the width of the button property real shapeMorphExpansion: shapeMorph && pressed ? 24 : 0 // Apparently it's always 24px no matter the width of the button
readonly property color onColour: disabled ? disabledOnColour : internalChecked ? activeOnColour : inactiveOnColour readonly property color onColour: disabled ? disabledOnColour : internalChecked ? activeOnColour : inactiveOnColour
property real pressedRadius: Tokens.rounding.small
property real checkedRadius: Tokens.rounding.medium
property real defaultRadius: Tokens.rounding.large
signal clicked signal clicked
onCheckedChanged: internalChecked = checked onCheckedChanged: internalChecked = checked
radius: { radius: {
if (radiusMorph && pressed) if (radiusMorph && pressed)
return Tokens.rounding.small; return pressedRadius;
if (internalChecked) if (internalChecked)
return Tokens.rounding.medium; return checkedRadius;
if (isRound) if (isRound)
return implicitHeight / 2 * Math.min(1, Tokens.rounding.scale); return implicitHeight / 2 * Math.min(1, Tokens.rounding.scale);
return Tokens.rounding.large; return defaultRadius;
} }
color: type === ButtonBase.Text ? "transparent" : disabled ? disabledColour : internalChecked ? activeColour : inactiveColour color: type === ButtonBase.Text ? "transparent" : disabled ? disabledColour : internalChecked ? activeColour : inactiveColour

View file

@ -1,12 +1,13 @@
pragma ComponentBehavior: Bound pragma ComponentBehavior: Bound
import QtQuick import QtQuick
import QtQuick.Layouts
import QtQuick.Shapes import QtQuick.Shapes
import Quickshell import Quickshell
import Quickshell.Services.Notifications import Quickshell.Services.Notifications
import Caelestia.Components
import Caelestia.Config import Caelestia.Config
import qs.components import qs.components
import qs.components.controls
import qs.components.effects import qs.components.effects
import qs.services import qs.services
import qs.utils import qs.utils
@ -18,7 +19,7 @@ StyledRect {
readonly property bool hasImage: modelData.image.length > 0 readonly property bool hasImage: modelData.image.length > 0
readonly property bool hasAppIcon: modelData.appIcon.length > 0 readonly property bool hasAppIcon: modelData.appIcon.length > 0
readonly property int bodyTextFormat: /[<*_`#\[\]]/.test(modelData.body) ? Text.MarkdownText : Text.PlainText readonly property int bodyTextFormat: /[<*_`#\[\]]/.test(modelData.body) ? Text.MarkdownText : Text.PlainText
readonly property int nonAnimHeight: summary.implicitHeight + (root.expanded ? appName.height + body.height + actions.height + actions.anchors.topMargin : bodyPreview.height) + inner.anchors.margins * 2 readonly property int nonAnimHeight: summary.implicitHeight + (root.expanded ? Tokens.spacing.extraSmall * 2 + appName.height + body.height + actions.height + actions.anchors.topMargin : bodyPreview.height) + inner.anchors.margins * 2
property bool expanded: Config.notifs.openExpanded property bool expanded: Config.notifs.openExpanded
color: root.modelData.urgency === NotificationUrgency.Critical ? Colours.palette.m3secondaryContainer : Colours.tPalette.m3surfaceContainer color: root.modelData.urgency === NotificationUrgency.Critical ? Colours.palette.m3secondaryContainer : Colours.tPalette.m3surfaceContainer
@ -234,7 +235,7 @@ StyledRect {
text: appNameMetrics.elidedText text: appNameMetrics.elidedText
maximumLineCount: 1 maximumLineCount: 1
color: Colours.palette.m3onSurfaceVariant color: Colours.palette.m3onSurfaceVariant
font: Tokens.font.label.small font: Tokens.font.label.medium
opacity: root.expanded ? 1 : 0 opacity: root.expanded ? 1 : 0
@ -272,6 +273,9 @@ StyledRect {
PropertyChanges { PropertyChanges {
summary.maximumLineCount: undefined summary.maximumLineCount: undefined
summary.anchors.topMargin: root.Tokens.spacing.extraSmall
bodyPreview.anchors.topMargin: root.Tokens.spacing.extraSmall
body.anchors.topMargin: root.Tokens.spacing.extraSmall
} }
AnchorChanges { AnchorChanges {
@ -285,9 +289,10 @@ StyledRect {
target: summary target: summary
property: "maximumLineCount" property: "maximumLineCount"
} }
AnchorAnim { Anim {
type: AnchorAnim.Standard property: "topMargin"
} }
AnchorAnim {}
} }
Behavior on height { Behavior on height {
@ -326,9 +331,7 @@ StyledRect {
} }
transitions: Transition { transitions: Transition {
AnchorAnim { AnchorAnim {}
type: AnchorAnim.Standard
}
} }
} }
@ -352,8 +355,8 @@ StyledRect {
anchors.right: parent.right anchors.right: parent.right
anchors.top: parent.top anchors.top: parent.top
implicitWidth: expandIcon.height implicitWidth: expandIcon.implicitHeight
implicitHeight: expandIcon.height implicitHeight: expandIcon.implicitHeight
StateLayer { StateLayer {
radius: Tokens.rounding.full radius: Tokens.rounding.full
@ -365,10 +368,13 @@ StyledRect {
id: expandIcon id: expandIcon
anchors.centerIn: parent anchors.centerIn: parent
text: "expand_more"
animate: true
text: root.expanded ? "expand_less" : "expand_more"
fontStyle: Tokens.font.icon.medium fontStyle: Tokens.font.icon.medium
rotation: root.expanded ? 180 : 0
Behavior on rotation {
Anim {}
}
} }
} }
@ -437,15 +443,15 @@ StyledRect {
} }
} }
RowLayout { ButtonRow {
id: actions id: actions
anchors.horizontalCenter: parent.horizontalCenter anchors.left: body.left
anchors.right: body.right
anchors.top: body.bottom anchors.top: body.bottom
anchors.topMargin: Tokens.spacing.small anchors.topMargin: Tokens.spacing.small
spacing: Tokens.spacing.medium spacing: Tokens.spacing.extraSmall
opacity: root.expanded ? 1 : 0 opacity: root.expanded ? 1 : 0
Behavior on opacity { Behavior on opacity {
@ -454,65 +460,62 @@ StyledRect {
} }
} }
Action { IconButton {
modelData: QtObject { isRound: true
readonly property string text: qsTr("Close") shapeMorph: true
fillWidth: root.modelData.actions.length === 0
function invoke(): void { inactiveColour: root.modelData.urgency === NotificationUrgency.Critical ? Colours.palette.m3secondary : Colours.layer(Colours.palette.m3surfaceContainerHighest, 2)
root.modelData.close(); inactiveOnColour: root.modelData.urgency === NotificationUrgency.Critical ? Colours.palette.m3onSecondary : Colours.palette.m3onSurfaceVariant
} icon: "close"
} padding: Tokens.padding.extraSmall
onClicked: root.modelData.close()
} }
Repeater { Repeater {
model: root.modelData.actions model: root.modelData.actions
delegate: Component { TextButton {
Action {} required property var modelData
isRound: true
shapeMorph: true
fillWidth: true
inactiveColour: root.modelData.urgency === NotificationUrgency.Critical ? Colours.palette.m3secondary : Colours.layer(Colours.palette.m3surfaceContainerHighest, 2)
inactiveOnColour: root.modelData.urgency === NotificationUrgency.Critical ? Colours.palette.m3onSecondary : Colours.palette.m3onSurfaceVariant
text: modelData.text
onClicked: modelData.invoke()
label.horizontalAlignment: Text.AlignHCenter
label.anchors.left: left
label.anchors.right: right
label.anchors.verticalCenter: verticalCenter
label.anchors.centerIn: undefined
label.anchors.margins: Tokens.padding.medium
label.elide: Text.ElideRight
}
}
IconButton {
isRound: true
shapeMorph: true
fillWidth: root.modelData.actions.length === 0
inactiveColour: root.modelData.urgency === NotificationUrgency.Critical ? Colours.palette.m3secondary : Colours.layer(Colours.palette.m3surfaceContainerHighest, 2)
inactiveOnColour: root.modelData.urgency === NotificationUrgency.Critical ? Colours.palette.m3onSecondary : Colours.palette.m3onSurfaceVariant
icon: copyTimer.running ? "inventory" : "content_copy"
padding: Tokens.padding.extraSmall
onClicked: {
Quickshell.clipboardText = root.modelData.body;
copyTimer.restart();
}
label.animate: true
Timer {
id: copyTimer
interval: 3000
} }
} }
} }
} }
} }
component Action: StyledRect {
id: action
required property var modelData
radius: Tokens.rounding.full
color: root.modelData.urgency === NotificationUrgency.Critical ? Colours.palette.m3secondary : Colours.layer(Colours.palette.m3surfaceContainerHigh, 2)
Layout.preferredWidth: actionText.width + Tokens.padding.medium * 2
Layout.preferredHeight: actionText.height + Tokens.padding.small
implicitWidth: actionText.width + Tokens.padding.medium * 2
implicitHeight: actionText.height + Tokens.padding.small
StateLayer {
radius: Tokens.rounding.full
color: root.modelData.urgency === NotificationUrgency.Critical ? Colours.palette.m3onSecondary : Colours.palette.m3onSurface
onClicked: action.modelData.invoke()
}
StyledText {
id: actionText
anchors.centerIn: parent
text: actionTextMetrics.elidedText
color: root.modelData.urgency === NotificationUrgency.Critical ? Colours.palette.m3onSecondary : Colours.palette.m3onSurfaceVariant
font: Tokens.font.label.small
}
TextMetrics {
id: actionTextMetrics
text: action.modelData.text
font: actionText.font
elide: Text.ElideRight
elideWidth: {
const numActions = root.modelData.actions.length + 1;
return (inner.width - actions.spacing * (numActions - 1)) / numActions - root.Tokens.padding.medium * 2;
}
}
}
} }