quickshell: uniform panelGap token + card-style notifications/toast

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
rope 2026-07-08 14:05:05 +01:00
parent 0342cbe59a
commit 1158a36d1a

View file

@ -184,6 +184,7 @@ in
readonly property int radiusSmall: 6 // workspace dots, pill buttons readonly property int radiusSmall: 6 // workspace dots, pill buttons
readonly property int radiusTiny: 4 // hover rows, action chips readonly property int radiusTiny: 4 // hover rows, action chips
readonly property int cardPad: 8 // card inner padding (inset = 2×) readonly property int cardPad: 8 // card inner padding (inset = 2×)
readonly property int panelGap: 8 // gap between panel border and cards (all dropdowns/menus/toast)
// Animation duration tokens (ms) // Animation duration tokens (ms)
readonly property int animMorph: 280 // panel grow / slide (OutExpo) readonly property int animMorph: 280 // panel grow / slide (OutExpo)
@ -949,8 +950,8 @@ in
// Both axes animate so the panel expands from a small // Both axes animate so the panel expands from a small
// point on the column (like the top dropdowns' stub seed) // point on the column (like the top dropdowns' stub seed)
// instead of rolling out at full height. // instead of rolling out at full height.
property real openW: open ? 64 : 0 property real openW: open ? sessionCard.width + 2 * Theme.panelGap : 0
property real openH: open ? sessionCard.height + 24 : 36 property real openH: open ? sessionCard.height + 2 * Theme.panelGap : 36
Behavior on openW { Behavior on openW {
NumberAnimation { duration: Theme.animMorph; easing.type: Easing.OutExpo } NumberAnimation { duration: Theme.animMorph; easing.type: Easing.OutExpo }
} }
@ -1009,7 +1010,7 @@ in
id: sessionCard id: sessionCard
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
anchors.right: parent.right anchors.right: parent.right
anchors.rightMargin: 8 anchors.rightMargin: Theme.panelGap
width: 48 width: 48
height: sessionCol.height + 8 height: sessionCol.height + 8
radius: Theme.radius radius: Theme.radius
@ -2048,8 +2049,8 @@ in
id: contextMenu id: contextMenu
alignRight: true alignRight: true
property var trayItem: null property var trayItem: null
fullWidth: menuItems.width + 24 fullWidth: menuItems.width + 2 * Theme.panelGap
fullHeight: menuItems.height + 16 fullHeight: menuItems.height + 2 * Theme.panelGap
onVisibleChanged: { onVisibleChanged: {
if (!visible) menuOpener.menu = null; if (!visible) menuOpener.menu = null;
@ -2132,8 +2133,8 @@ in
BarDropdown { BarDropdown {
id: volDropdown id: volDropdown
alignRight: true alignRight: true
fullWidth: volDropdownCol.width + 28 fullWidth: volDropdownCol.width + 2 * Theme.panelGap
fullHeight: volDropdownCol.height + 20 fullHeight: volDropdownCol.height + 2 * Theme.panelGap
Column { Column {
id: volDropdownCol id: volDropdownCol
@ -2289,8 +2290,8 @@ in
BarDropdown { BarDropdown {
id: netDropdown id: netDropdown
alignRight: true alignRight: true
fullWidth: netDropdownCol.width + 28 fullWidth: netDropdownCol.width + 2 * Theme.panelGap
fullHeight: netDropdownCol.height + 20 fullHeight: netDropdownCol.height + 2 * Theme.panelGap
Column { Column {
id: netDropdownCol id: netDropdownCol
@ -2424,8 +2425,8 @@ in
BarDropdown { BarDropdown {
id: batteryDropdown id: batteryDropdown
alignRight: true alignRight: true
fullWidth: batteryDropdownCol.width + 28 fullWidth: batteryDropdownCol.width + 2 * Theme.panelGap
fullHeight: batteryDropdownCol.height + 20 fullHeight: batteryDropdownCol.height + 2 * Theme.panelGap
Column { Column {
id: batteryDropdownCol id: batteryDropdownCol
@ -2624,8 +2625,8 @@ in
BarDropdown { BarDropdown {
id: qsDropdown id: qsDropdown
alignRight: true alignRight: true
fullWidth: qsCol.width + 28 fullWidth: qsCol.width + 2 * Theme.panelGap
fullHeight: qsCol.height + 20 fullHeight: qsCol.height + 2 * Theme.panelGap
Column { Column {
id: qsCol id: qsCol
@ -2645,8 +2646,8 @@ in
dropdownX: bar.width / 2 dropdownX: bar.width / 2
// ceil: Text metrics give fractional sizes; fractional rect // ceil: Text metrics give fractional sizes; fractional rect
// edges render as soft 2px lines // edges render as soft 2px lines
fullWidth: Math.ceil(calRow.width) + 24 fullWidth: Math.ceil(calRow.width) + 2 * Theme.panelGap
fullHeight: Math.ceil(calRow.height + 8 + notifCard.height) + 24 fullHeight: Math.ceil(calRow.height + 8 + notifCard.height) + 2 * Theme.panelGap
// Month being viewed; reset to today when the popup opens // Month being viewed; reset to today when the popup opens
// (via the setup function passed to bar.toggleDropdown). // (via the setup function passed to bar.toggleDropdown).
@ -3060,27 +3061,31 @@ in
} }
} }
// Notifications: spans both columns, below the panes // Notifications: spans both columns, below the panes.
Card { // Header + one Card per notification, matching the media
// cards instead of base02 blocks nested inside a big card.
Column {
id: notifCard id: notifCard
anchors.top: calRow.bottom anchors.top: calRow.bottom
anchors.topMargin: 8 anchors.topMargin: 8
anchors.horizontalCenter: parent.horizontalCenter anchors.horizontalCenter: parent.horizontalCenter
width: calRow.width width: calRow.width
opacity: calRow.opacity opacity: calRow.opacity
cardSpacing: 6 spacing: 8
Item { Item {
width: parent.width width: parent.width
height: 20 height: 20
SText { SText {
anchors.left: parent.left anchors.left: parent.left
anchors.leftMargin: Theme.cardPad
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
text: "Notifications" text: "Notifications"
font.weight: Font.Medium font.weight: Font.Medium
} }
SText { SText {
anchors.right: parent.right anchors.right: parent.right
anchors.rightMargin: Theme.cardPad
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
text: bar.notifServer.trackedNotifications.values.length > 0 ? "Clear all" : "" text: bar.notifServer.trackedNotifications.values.length > 0 ? "Clear all" : ""
color: Theme.base04 color: Theme.base04
@ -3109,55 +3114,56 @@ in
Repeater { Repeater {
model: bar.notifServer.trackedNotifications model: bar.notifServer.trackedNotifications
Rectangle { Card {
id: notifItem id: notifItem
required property var modelData required property var modelData
readonly property string previewSource: bar.notifPreviewSource(notifItem.modelData) readonly property string previewSource: bar.notifPreviewSource(notifItem.modelData)
width: parent.width width: parent.width
height: Math.max(notifPreview.visible ? 48 : 0, ncBody.height) + 16
radius: Theme.radiusSmall
color: Theme.base02
// Image preview (album art, screenshot thumb) Item {
ClippingRectangle { width: parent.width
id: notifPreview height: Math.max(notifPreview.visible ? 48 : 0, ncBody.height)
visible: notifItem.previewSource !== ""
anchors.left: parent.left // Image preview (album art, screenshot thumb)
anchors.top: parent.top ClippingRectangle {
anchors.margins: 8 id: notifPreview
width: 48; height: 48 visible: notifItem.previewSource !== ""
radius: Theme.radiusTiny anchors.left: parent.left
color: Theme.base01 anchors.top: parent.top
Image { width: 48; height: 48
anchors.fill: parent radius: Theme.radiusTiny
fillMode: Image.PreserveAspectCrop color: Theme.base01
source: notifItem.previewSource Image {
anchors.fill: parent
fillMode: Image.PreserveAspectCrop
source: notifItem.previewSource
}
} }
}
NotifContent { NotifContent {
id: ncBody id: ncBody
notif: notifItem.modelData notif: notifItem.modelData
anchors.left: notifPreview.visible ? notifPreview.right : parent.left anchors.left: notifPreview.visible ? notifPreview.right : parent.left
anchors.right: dismissBtn.left anchors.leftMargin: notifPreview.visible ? 8 : 0
anchors.top: parent.top anchors.right: dismissBtn.left
anchors.margins: 8 anchors.rightMargin: 8
} anchors.top: parent.top
}
SIcon { SIcon {
id: dismissBtn id: dismissBtn
anchors.right: parent.right anchors.right: parent.right
anchors.top: parent.top anchors.top: parent.top
anchors.margins: 8 text: "close"
text: "close" color: dismissMa.containsMouse ? Theme.base05 : Theme.base03
color: dismissMa.containsMouse ? Theme.base05 : Theme.base03 font.pixelSize: 15
font.pixelSize: 15 MouseArea {
MouseArea { id: dismissMa
id: dismissMa anchors.fill: parent
anchors.fill: parent hoverEnabled: true
hoverEnabled: true cursorShape: Qt.PointingHandCursor
cursorShape: Qt.PointingHandCursor onClicked: notifItem.modelData.dismiss()
onClicked: notifItem.modelData.dismiss() }
} }
} }
} }
@ -3248,24 +3254,24 @@ in
anchors.horizontalCenter: parent.horizontalCenter anchors.horizontalCenter: parent.horizontalCenter
anchors.top: parent.top anchors.top: parent.top
width: 320 width: 320
height: toastItem.toastOpen ? toastCard.height + 12 : 0 height: toastItem.toastOpen ? toastCard.height + 2 * Theme.panelGap : 0
clip: true clip: true
Behavior on height { Behavior on height {
NumberAnimation { duration: Theme.animMorph; easing.type: Easing.OutExpo } NumberAnimation { duration: Theme.animMorph; easing.type: Easing.OutExpo }
} }
// Notification sits in a base02 rounded card, matching // Notification sits in a cardBg card like every other
// the calendar list. Inset 6px so the melt panel frames it. // dropdown surface, inset panelGap from the melt panel.
Rectangle { Rectangle {
id: toastCard id: toastCard
anchors.top: parent.top anchors.top: parent.top
anchors.left: parent.left anchors.left: parent.left
anchors.right: parent.right anchors.right: parent.right
anchors.margins: 6 anchors.margins: Theme.panelGap
height: Math.max(toastPreview.visible ? 48 : 0, toastCol.height) + 16 height: Math.max(toastPreview.visible ? 48 : 0, toastCol.height) + 16
radius: Theme.radiusSmall radius: Theme.radius
color: Theme.base02 color: Theme.cardBg
property string previewSource: bar.notifPreviewSource(toastItem.currentNotif) property string previewSource: bar.notifPreviewSource(toastItem.currentNotif)