Colors and Notifications
This commit is contained in:
15
Colors.qml
Normal file
15
Colors.qml
Normal file
@@ -0,0 +1,15 @@
|
||||
pragma Singleton
|
||||
|
||||
import QtQuick
|
||||
|
||||
// Everforest Dark Hard — edit here to retheme the whole bar.
|
||||
QtObject {
|
||||
readonly property color bg: "#2d353b" // bar background, text on highlights
|
||||
readonly property color bgDark: "#272e33" // popup background
|
||||
readonly property color surface: "#343f44" // inactive workspace pill, hover bg
|
||||
readonly property color fg: "#d3c6aa" // primary text and icons
|
||||
readonly property color fgDim: "#7a8478" // separators, weekday labels, muted/offline
|
||||
readonly property color accent: "#a7c080" // active workspace, today, nav arrows
|
||||
readonly property color warning: "#e69875" // moderate load
|
||||
readonly property color critical: "#e67e80" // high load, low battery, weekends
|
||||
}
|
||||
@@ -3,6 +3,7 @@ pragma ComponentBehavior: Bound
|
||||
import Quickshell
|
||||
import QtQuick
|
||||
import QtQuick.Layouts
|
||||
import ".."
|
||||
|
||||
PanelWindow {
|
||||
id: root
|
||||
@@ -16,7 +17,7 @@ PanelWindow {
|
||||
implicitHeight: 32
|
||||
exclusionMode: ExclusionMode.Auto
|
||||
|
||||
color: "#1e1e2e"
|
||||
color: Colors.bg
|
||||
|
||||
// Left side — anchored to left edge, never affected by right side width
|
||||
RowLayout {
|
||||
|
||||
@@ -3,6 +3,7 @@ pragma ComponentBehavior: Bound
|
||||
import Quickshell
|
||||
import QtQuick
|
||||
import QtQuick.Layouts
|
||||
import ".."
|
||||
|
||||
// Calendar popup — anchored below its trigger item.
|
||||
// Instantiate inside DateTime.qml; set anchor.window + anchor.item from there.
|
||||
@@ -15,7 +16,7 @@ PopupWindow {
|
||||
visible: false
|
||||
color: "transparent"
|
||||
|
||||
implicitWidth: 252 // 7 columns × 36 px
|
||||
implicitWidth: 276 // 7 columns × 36 px + 12 px margin on each side
|
||||
implicitHeight: 284
|
||||
|
||||
// ── State ────────────────────────────────────────────────────────────────
|
||||
@@ -24,7 +25,7 @@ PopupWindow {
|
||||
|
||||
// ── Public API ───────────────────────────────────────────────────────────
|
||||
function open() {
|
||||
// Reset animation state before the window becomes visible.
|
||||
// Reset content state in case closeAnim ran previously.
|
||||
content.opacity = 0;
|
||||
content.scale = 0.95;
|
||||
closeAnim.stop();
|
||||
@@ -114,7 +115,7 @@ PopupWindow {
|
||||
// ── Background ───────────────────────────────────────────────────────
|
||||
Rectangle {
|
||||
anchors.fill: parent
|
||||
color: "#181825" // Catppuccin Mantle
|
||||
color: Colors.bgDark
|
||||
radius: 8
|
||||
}
|
||||
|
||||
@@ -127,63 +128,35 @@ PopupWindow {
|
||||
spacing: 8
|
||||
|
||||
// ── Month navigation ─────────────────────────────────────────────
|
||||
component NavButton: Rectangle {
|
||||
required property string label
|
||||
required property var action
|
||||
width: 24; height: 24; radius: 4
|
||||
color: hover.hovered ? Colors.surface : "transparent"
|
||||
Text {
|
||||
anchors.centerIn: parent
|
||||
text: parent.label
|
||||
color: Colors.accent
|
||||
font.pixelSize: 16
|
||||
font.weight: Font.Bold
|
||||
}
|
||||
HoverHandler { id: hover }
|
||||
TapHandler { onTapped: parent.action() }
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
width: parent.width
|
||||
|
||||
Rectangle {
|
||||
width: 24
|
||||
height: 24
|
||||
radius: 4
|
||||
color: prevHover.hovered ? "#313244" : "transparent"
|
||||
Text {
|
||||
anchors.centerIn: parent
|
||||
text: "‹"
|
||||
color: "#89b4fa"
|
||||
font.pixelSize: 16
|
||||
font.weight: Font.Bold
|
||||
}
|
||||
HoverHandler {
|
||||
id: prevHover
|
||||
}
|
||||
TapHandler {
|
||||
onTapped: root.prevMonth()
|
||||
}
|
||||
}
|
||||
|
||||
Item {
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
|
||||
NavButton { label: "‹"; action: root.prevMonth }
|
||||
Item { Layout.fillWidth: true }
|
||||
Text {
|
||||
text: root.monthNames[root.viewMonth] + " " + root.viewYear
|
||||
color: "#cdd6f4"
|
||||
color: Colors.fg
|
||||
font.pixelSize: 13
|
||||
font.weight: Font.Medium
|
||||
}
|
||||
|
||||
Item {
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
width: 24
|
||||
height: 24
|
||||
radius: 4
|
||||
color: nextHover.hovered ? "#313244" : "transparent"
|
||||
Text {
|
||||
anchors.centerIn: parent
|
||||
text: "›"
|
||||
color: "#89b4fa"
|
||||
font.pixelSize: 16
|
||||
font.weight: Font.Bold
|
||||
}
|
||||
HoverHandler {
|
||||
id: nextHover
|
||||
}
|
||||
TapHandler {
|
||||
onTapped: root.nextMonth()
|
||||
}
|
||||
}
|
||||
Item { Layout.fillWidth: true }
|
||||
NavButton { label: "›"; action: root.nextMonth }
|
||||
}
|
||||
|
||||
// ── Day-of-week header ────────────────────────────────────────────
|
||||
@@ -197,7 +170,7 @@ PopupWindow {
|
||||
width: 36
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
text: modelData
|
||||
color: index >= 5 ? "#f38ba8" : "#6c7086"
|
||||
color: index >= 5 ? Colors.critical : Colors.fgDim
|
||||
font.pixelSize: 11
|
||||
}
|
||||
}
|
||||
@@ -243,7 +216,7 @@ PopupWindow {
|
||||
width: 28
|
||||
height: 28
|
||||
radius: 14
|
||||
color: cell.isToday ? "#89b4fa" : "transparent"
|
||||
color: cell.isToday ? Colors.accent : "transparent"
|
||||
}
|
||||
|
||||
Text {
|
||||
@@ -254,10 +227,10 @@ PopupWindow {
|
||||
font.weight: cell.isToday ? Font.Bold : Font.Normal
|
||||
color: {
|
||||
if (cell.isToday)
|
||||
return "#1e1e2e";
|
||||
return Colors.bg;
|
||||
if (cell.isWeekend)
|
||||
return "#f38ba8";
|
||||
return "#cdd6f4";
|
||||
return Colors.critical;
|
||||
return Colors.fg;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
pragma ComponentBehavior: Bound
|
||||
|
||||
import Quickshell
|
||||
import Quickshell.Wayland
|
||||
import QtQuick
|
||||
import QtQuick.Layouts
|
||||
import ".."
|
||||
|
||||
// Date + time widget. Click it to open/close the calendar popup.
|
||||
// barWindow must be set by the parent (Bar.qml) so the popup has a Wayland parent.
|
||||
@@ -20,24 +22,45 @@ RowLayout {
|
||||
|
||||
anchor.window: root.barWindow
|
||||
anchor.item: root
|
||||
anchor.edges: Edges.Bottom
|
||||
anchor.edges: Edges.Bottom | Edges.Right
|
||||
anchor.gravity: Edges.Bottom | Edges.Left
|
||||
}
|
||||
|
||||
// Full-screen transparent overlay: captures outside clicks and Escape to close calendar.
|
||||
// WlrLayershell.keyboardFocus: Exclusive gives it real keyboard focus from the compositor.
|
||||
PanelWindow {
|
||||
visible: cal.visible
|
||||
screen: root.barWindow.screen
|
||||
color: "transparent"
|
||||
exclusionMode: ExclusionMode.Ignore
|
||||
anchors { top: true; bottom: true; left: true; right: true }
|
||||
WlrLayershell.keyboardFocus: WlrKeyboardFocus.Exclusive
|
||||
|
||||
TapHandler {
|
||||
onTapped: cal.close()
|
||||
}
|
||||
|
||||
Item {
|
||||
focus: true
|
||||
Keys.onEscapePressed: cal.close()
|
||||
}
|
||||
}
|
||||
|
||||
Text {
|
||||
id: dateLabel
|
||||
color: "#a6adc8"
|
||||
color: Colors.fg
|
||||
font.pixelSize: 13
|
||||
}
|
||||
|
||||
Text {
|
||||
text: "|"
|
||||
color: "#45475a"
|
||||
color: Colors.fgDim
|
||||
font.pixelSize: 13
|
||||
}
|
||||
|
||||
Text {
|
||||
id: timeLabel
|
||||
color: "#cdd6f4"
|
||||
color: Colors.fg
|
||||
font.pixelSize: 13
|
||||
font.weight: Font.Medium
|
||||
Behavior on color {
|
||||
|
||||
@@ -4,6 +4,7 @@ import Quickshell
|
||||
import Quickshell.Io
|
||||
import QtQuick
|
||||
import QtQuick.Layouts
|
||||
import ".."
|
||||
|
||||
// System stats strip: Volume · Network · CPU load · Memory · Temperature · Brightness · Battery
|
||||
// All stats refreshed every 5 s via a single bash process.
|
||||
@@ -20,6 +21,7 @@ RowLayout {
|
||||
property int cpuCores: 1
|
||||
property real memUsedGB: 0
|
||||
property real memTotalGB: 0
|
||||
readonly property real memRatio: memTotalGB > 0 ? memUsedGB / memTotalGB : 0
|
||||
property int tempC: 0
|
||||
property int brightPct: 100
|
||||
property int batPct: -1 // -1 means no battery detected
|
||||
@@ -113,8 +115,9 @@ RowLayout {
|
||||
}
|
||||
|
||||
// ── Volume ────────────────────────────────────────────────────────────────
|
||||
RowLayout {
|
||||
spacing: 4
|
||||
Item {
|
||||
implicitWidth: volRow.implicitWidth
|
||||
implicitHeight: volRow.implicitHeight
|
||||
|
||||
Process { id: pavucontrolProc; command: ["pavucontrol"] }
|
||||
Process { id: volUpProc; command: ["pactl", "set-sink-volume", "@DEFAULT_SINK@", "+5%"] }
|
||||
@@ -137,15 +140,21 @@ RowLayout {
|
||||
}
|
||||
}
|
||||
|
||||
Text {
|
||||
text: root.volMuted ? "" : (root.volPct > 50 ? "" : root.volPct > 0 ? "" : "")
|
||||
color: root.volMuted ? "#585b70" : "#cdd6f4"
|
||||
font.pixelSize: 15
|
||||
}
|
||||
Text {
|
||||
text: root.volMuted ? "mute" : root.volPct + "%"
|
||||
color: "#a6adc8"
|
||||
font.pixelSize: 13
|
||||
RowLayout {
|
||||
id: volRow
|
||||
anchors.fill: parent
|
||||
spacing: 4
|
||||
|
||||
Text {
|
||||
text: root.volMuted ? "" : (root.volPct > 50 ? "" : root.volPct > 0 ? "" : "")
|
||||
color: root.volMuted ? Colors.fgDim : Colors.fg
|
||||
font.pixelSize: 15
|
||||
}
|
||||
Text {
|
||||
text: root.volMuted ? "mute" : root.volPct + "%"
|
||||
color: Colors.fg
|
||||
font.pixelSize: 13
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -154,13 +163,13 @@ RowLayout {
|
||||
spacing: 4
|
||||
Text {
|
||||
text: root.netIp ? "" : ""
|
||||
color: root.netIp ? "#cdd6f4" : "#585b70"
|
||||
color: root.netIp ? Colors.fg : Colors.fgDim
|
||||
font.pixelSize: 15
|
||||
}
|
||||
Text {
|
||||
visible: root.netIp !== ""
|
||||
text: root.netIp
|
||||
color: "#a6adc8"
|
||||
color: Colors.fg
|
||||
font.pixelSize: 13
|
||||
}
|
||||
}
|
||||
@@ -168,11 +177,11 @@ RowLayout {
|
||||
// ── CPU load average ──────────────────────────────────────────────────────
|
||||
RowLayout {
|
||||
spacing: 4
|
||||
Text { text: ""; color: "#cdd6f4"; font.pixelSize: 15 }
|
||||
Text { text: ""; color: Colors.fg; font.pixelSize: 15 }
|
||||
Text {
|
||||
text: root.loadAvg.toFixed(2)
|
||||
color: root.loadAvg > root.cpuCores ? "#f38ba8" :
|
||||
root.loadAvg > root.cpuCores * 0.7 ? "#fab387" : "#a6adc8"
|
||||
color: root.loadAvg > root.cpuCores ? Colors.critical :
|
||||
root.loadAvg > root.cpuCores * 0.7 ? Colors.warning : Colors.fg
|
||||
font.pixelSize: 13
|
||||
}
|
||||
}
|
||||
@@ -180,11 +189,11 @@ RowLayout {
|
||||
// ── Memory ────────────────────────────────────────────────────────────────
|
||||
RowLayout {
|
||||
spacing: 4
|
||||
Text { text: ""; color: "#cdd6f4"; font.pixelSize: 15 }
|
||||
Text { text: ""; color: Colors.fg; font.pixelSize: 15 }
|
||||
Text {
|
||||
text: root.memUsedGB.toFixed(1) + "/" + root.memTotalGB.toFixed(1) + "G"
|
||||
color: root.memTotalGB > 0 && (root.memUsedGB / root.memTotalGB) > 0.8 ? "#f38ba8" :
|
||||
root.memTotalGB > 0 && (root.memUsedGB / root.memTotalGB) > 0.6 ? "#fab387" : "#a6adc8"
|
||||
color: root.memRatio > 0.8 ? Colors.critical :
|
||||
root.memRatio > 0.6 ? Colors.warning : Colors.fg
|
||||
font.pixelSize: 13
|
||||
}
|
||||
}
|
||||
@@ -192,10 +201,10 @@ RowLayout {
|
||||
// ── Temperature ───────────────────────────────────────────────────────────
|
||||
RowLayout {
|
||||
spacing: 4
|
||||
Text { text: ""; color: "#cdd6f4"; font.pixelSize: 15 }
|
||||
Text { text: ""; color: Colors.fg; font.pixelSize: 15 }
|
||||
Text {
|
||||
text: root.tempC + "°"
|
||||
color: root.tempC > 85 ? "#f38ba8" : root.tempC > 65 ? "#fab387" : "#a6adc8"
|
||||
color: root.tempC > 85 ? Colors.critical : root.tempC > 65 ? Colors.warning : Colors.fg
|
||||
font.pixelSize: 13
|
||||
}
|
||||
}
|
||||
@@ -203,10 +212,10 @@ RowLayout {
|
||||
// ── Brightness ────────────────────────────────────────────────────────────
|
||||
RowLayout {
|
||||
spacing: 4
|
||||
Text { text: ""; color: "#cdd6f4"; font.pixelSize: 15 }
|
||||
Text { text: ""; color: Colors.fg; font.pixelSize: 15 }
|
||||
Text {
|
||||
text: root.brightPct + "%"
|
||||
color: "#a6adc8"
|
||||
color: Colors.fg
|
||||
font.pixelSize: 13
|
||||
}
|
||||
}
|
||||
@@ -221,12 +230,12 @@ RowLayout {
|
||||
root.batPct > 60 ? "" :
|
||||
root.batPct > 40 ? "" :
|
||||
root.batPct > 20 ? "" : ""
|
||||
color: root.batPct < 20 && root.batStatus !== "Charging" ? "#f38ba8" : "#cdd6f4"
|
||||
color: root.batPct < 20 && root.batStatus !== "Charging" ? Colors.critical : Colors.fg
|
||||
font.pixelSize: 15
|
||||
}
|
||||
Text {
|
||||
text: root.batTime ? root.batPct + "% · " + root.batTime : root.batPct + "%"
|
||||
color: root.batPct < 20 && root.batStatus !== "Charging" ? "#f38ba8" : "#a6adc8"
|
||||
color: root.batPct < 20 && root.batStatus !== "Charging" ? Colors.critical : Colors.fg
|
||||
font.pixelSize: 13
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ import Quickshell
|
||||
import Quickshell.Hyprland
|
||||
import QtQuick
|
||||
import QtQuick.Layouts
|
||||
import ".."
|
||||
|
||||
// A row of clickable workspace buttons for one screen.
|
||||
// The button for the workspace currently active on *this* screen is highlighted.
|
||||
@@ -26,18 +27,13 @@ RowLayout {
|
||||
required property HyprlandWorkspace modelData
|
||||
|
||||
readonly property bool isActive: root.monitor ? (root.monitor.activeWorkspace?.id === modelData.id) : modelData.focused
|
||||
readonly property bool isUrgent: modelData.urgent
|
||||
|
||||
implicitWidth: Math.max(28, label.implicitWidth + 16)
|
||||
implicitHeight: 22
|
||||
radius: 4
|
||||
|
||||
color: {
|
||||
if (isActive)
|
||||
return "#89b4fa";
|
||||
if (hoverArea.hovered)
|
||||
return "#45475a";
|
||||
return "#313244";
|
||||
}
|
||||
color: isActive ? Colors.accent : isUrgent ? Colors.warning : Colors.surface
|
||||
|
||||
Behavior on color {
|
||||
ColorAnimation {
|
||||
@@ -49,7 +45,7 @@ RowLayout {
|
||||
id: label
|
||||
anchors.centerIn: parent
|
||||
text: btn.modelData.name
|
||||
color: btn.isActive ? "#1e1e2e" : "#cdd6f4" // Base / Text
|
||||
color: (btn.isActive || btn.isUrgent) ? Colors.bg : Colors.fg
|
||||
font.pixelSize: 13
|
||||
font.weight: btn.isActive ? Font.Bold : Font.Normal
|
||||
|
||||
|
||||
255
notifications/NotificationPopups.qml
Normal file
255
notifications/NotificationPopups.qml
Normal file
@@ -0,0 +1,255 @@
|
||||
pragma ComponentBehavior: Bound
|
||||
|
||||
import Quickshell
|
||||
import Quickshell.Services.Notifications
|
||||
import Quickshell.Widgets
|
||||
import QtQuick
|
||||
import QtQuick.Layouts
|
||||
import ".."
|
||||
|
||||
// Notification toast overlay.
|
||||
// Toasts slide in from the right, stack downward, and auto-dismiss.
|
||||
// Urgency colouring: Low → fgDim stripe, Normal → accent stripe, Critical → critical border + stripe.
|
||||
|
||||
PanelWindow {
|
||||
id: root
|
||||
|
||||
anchors {
|
||||
top: true
|
||||
right: true
|
||||
}
|
||||
exclusionMode: ExclusionMode.Ignore
|
||||
color: "transparent"
|
||||
|
||||
implicitWidth: 356 // 340 toast + 8 left + 8 right margin
|
||||
implicitHeight: Math.max(1, (clearAllBtn.visible ? clearAllBtn.height + 6 : 0) + notifList.contentHeight + 16)
|
||||
|
||||
// ── Notification server ──────────────────────────────────────────────────
|
||||
NotificationServer {
|
||||
id: server
|
||||
|
||||
onNotification: function (notif) {
|
||||
notifModel.insert(0, {
|
||||
"nid": notif.id,
|
||||
"app": notif.appName,
|
||||
"icon": notif.appIcon,
|
||||
"summary": notif.summary !== "" ? notif.summary : notif.appName,
|
||||
"body": notif.body,
|
||||
"urgency": notif.urgency
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
ListModel {
|
||||
id: notifModel
|
||||
}
|
||||
|
||||
function removeById(nid) {
|
||||
for (let i = 0; i < notifModel.count; i++) {
|
||||
if (notifModel.get(i).nid === nid) {
|
||||
notifModel.remove(i);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ── Toast list ───────────────────────────────────────────────────────────
|
||||
// ── Clear all button (visible when 2+ notifications) ────────────────────
|
||||
Rectangle {
|
||||
id: clearAllBtn
|
||||
visible: notifModel.count >= 2
|
||||
anchors { top: parent.top; right: parent.right; topMargin: 8; rightMargin: 8 }
|
||||
width: 340
|
||||
height: 26
|
||||
color: clearHover.hovered ? Colors.surface : Colors.bgDark
|
||||
border.color: Colors.surface
|
||||
border.width: 1
|
||||
radius: 6
|
||||
|
||||
Text {
|
||||
anchors.centerIn: parent
|
||||
text: "Clear all (" + notifModel.count + ")"
|
||||
color: Colors.fgDim
|
||||
font.pixelSize: 12
|
||||
}
|
||||
|
||||
HoverHandler { id: clearHover }
|
||||
TapHandler { onTapped: notifModel.clear() }
|
||||
}
|
||||
|
||||
ListView {
|
||||
id: notifList
|
||||
anchors {
|
||||
top: clearAllBtn.visible ? clearAllBtn.bottom : parent.top
|
||||
right: parent.right
|
||||
topMargin: clearAllBtn.visible ? 6 : 8
|
||||
rightMargin: 8
|
||||
}
|
||||
width: 340
|
||||
height: contentHeight
|
||||
model: notifModel
|
||||
spacing: 6
|
||||
interactive: false
|
||||
|
||||
add: Transition {
|
||||
NumberAnimation {
|
||||
property: "x"
|
||||
from: 356
|
||||
to: 0
|
||||
duration: 220
|
||||
easing.type: Easing.OutCubic
|
||||
}
|
||||
NumberAnimation {
|
||||
property: "opacity"
|
||||
from: 0
|
||||
to: 1
|
||||
duration: 180
|
||||
}
|
||||
}
|
||||
|
||||
remove: Transition {
|
||||
NumberAnimation {
|
||||
property: "opacity"
|
||||
to: 0
|
||||
duration: 130
|
||||
easing.type: Easing.InCubic
|
||||
}
|
||||
NumberAnimation {
|
||||
property: "x"
|
||||
to: 356
|
||||
duration: 180
|
||||
easing.type: Easing.InCubic
|
||||
}
|
||||
}
|
||||
|
||||
displaced: Transition {
|
||||
NumberAnimation {
|
||||
properties: "y"
|
||||
duration: 220
|
||||
easing.type: Easing.OutCubic
|
||||
}
|
||||
NumberAnimation {
|
||||
property: "opacity"
|
||||
to: 1
|
||||
duration: 220
|
||||
}
|
||||
}
|
||||
|
||||
delegate: Item {
|
||||
id: toast
|
||||
required property int index
|
||||
required property int nid
|
||||
required property string app
|
||||
required property string icon
|
||||
required property string summary
|
||||
required property string body
|
||||
required property int urgency
|
||||
|
||||
width: 340
|
||||
height: toastBg.height
|
||||
|
||||
// ── Background card ──────────────────────────────────────────────
|
||||
Rectangle {
|
||||
id: toastBg
|
||||
width: parent.width
|
||||
height: cardContent.implicitHeight + 20
|
||||
color: Colors.bgDark
|
||||
border.color: toast.urgency === 2 ? Colors.critical : Colors.surface
|
||||
border.width: 1
|
||||
radius: 8
|
||||
|
||||
// Urgency stripe on left edge
|
||||
Rectangle {
|
||||
anchors {
|
||||
left: parent.left
|
||||
top: parent.top
|
||||
bottom: parent.bottom
|
||||
topMargin: 1
|
||||
bottomMargin: 1
|
||||
leftMargin: 1
|
||||
}
|
||||
width: 3
|
||||
radius: 8
|
||||
color: toast.urgency === 0 ? Colors.fgDim : toast.urgency === 2 ? Colors.critical : Colors.accent
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
id: cardContent
|
||||
anchors {
|
||||
left: parent.left
|
||||
right: parent.right
|
||||
top: parent.top
|
||||
leftMargin: 14
|
||||
rightMargin: 10
|
||||
topMargin: 10
|
||||
}
|
||||
spacing: 4
|
||||
|
||||
// ── Header row: icon + summary + app name + close button ─
|
||||
RowLayout {
|
||||
Layout.fillWidth: true
|
||||
spacing: 6
|
||||
|
||||
// App icon (shown when available)
|
||||
IconImage {
|
||||
visible: toast.icon !== ""
|
||||
source: toast.icon
|
||||
width: 16
|
||||
height: 16
|
||||
mipmap: true
|
||||
}
|
||||
|
||||
Text {
|
||||
text: toast.summary
|
||||
color: toast.urgency === 2 ? Colors.critical : toast.urgency === 0 ? Colors.fgDim : Colors.accent
|
||||
font.pixelSize: 13
|
||||
font.weight: Font.Medium
|
||||
Layout.fillWidth: true
|
||||
elide: Text.ElideRight
|
||||
}
|
||||
|
||||
Text {
|
||||
text: toast.app
|
||||
color: Colors.fgDim
|
||||
font.pixelSize: 11
|
||||
elide: Text.ElideRight
|
||||
Layout.maximumWidth: 90
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
width: 18
|
||||
height: 18
|
||||
radius: 4
|
||||
color: closeHover.hovered ? Colors.surface : "transparent"
|
||||
HoverHandler {
|
||||
id: closeHover
|
||||
}
|
||||
TapHandler {
|
||||
onTapped: root.removeById(toast.nid)
|
||||
}
|
||||
Text {
|
||||
anchors.centerIn: parent
|
||||
text: "✕"
|
||||
color: Colors.fgDim
|
||||
font.pixelSize: 11
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ── Body text ────────────────────────────────────────────
|
||||
Text {
|
||||
visible: toast.body !== ""
|
||||
text: toast.body
|
||||
color: Colors.fg
|
||||
font.pixelSize: 12
|
||||
Layout.fillWidth: true
|
||||
wrapMode: Text.WordWrap
|
||||
maximumLineCount: 3
|
||||
elide: Text.ElideRight
|
||||
bottomPadding: 2
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4,8 +4,9 @@ pragma ComponentBehavior: Bound
|
||||
import Quickshell
|
||||
import QtQuick
|
||||
import "bar"
|
||||
import "notifications"
|
||||
|
||||
// Root scope — creates one Bar per connected screen.
|
||||
// Root scope — creates one Bar per connected screen plus a single notification overlay.
|
||||
Scope {
|
||||
Variants {
|
||||
model: Quickshell.screens
|
||||
@@ -15,4 +16,6 @@ Scope {
|
||||
screen: modelData
|
||||
}
|
||||
}
|
||||
|
||||
NotificationPopups {}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user