Krolyxon
Commit 8ab0f85

Branches

Refs →

aurora8ab0f85

aurora: nothing os redesign, phase 2 (floating bar, calendar, edge osd, notification island)

Bar is a floating pill: dotted-ring mark (runner; live while recording/listening, flashes on
new notifications), workspace dots, Doto clock, battery capsule. Calendar card, right-edge
Glyph-strip OSD, notification island with hover hold. Tray menus need UseQApplication.
Author
krolyxon
Date
2026-10-28 20:01 +0530
Parent
ed4e5ea
Commit
8ab0f8516a2e243b6eaaea32e54f1bd300835a34

+586 −227

12 files changed

  1. M .config/quickshell/aurora/Bar.qml +140 −39
  2. M .config/quickshell/aurora/BarPill.qml +21 −27
  3. M .config/quickshell/aurora/CalPopup.qml +68 −61
  4. M .config/quickshell/aurora/NotifPopups.qml +232 −14
  5. M .config/quickshell/aurora/Notifs.qml +7 −0
  6. M .config/quickshell/aurora/Osd.qml +75 −42
  7. M .config/quickshell/aurora/SetAppearance.qml +1 −1
  8. M .config/quickshell/aurora/Settings.qml +3 −1
  9. M .config/quickshell/aurora/Theme.qml +3 −1
  10. M .config/quickshell/aurora/Tray.qml +11 −14
  11. M .config/quickshell/aurora/Workspaces.qml +23 −27
  12. M .config/quickshell/aurora/shell.qml +2 −0
M .config/quickshell/aurora/Bar.qml View
@@ -6,6 +6,12 @@ import Quickshell.Hyprland
66 import Quickshell.Services.Pipewire
77 import Quickshell.Services.UPower
88
9+// The bar: a floating pill at the top of every monitor.
10+// Left: the mark (a dotted ring: click = runner; its centre turns the live colour while something records or listens,
11+// the ring lights up in a wave on a new notification), this monitor's workspaces as dots, the cat.
12+// Centre: the active window (focused monitor only). Right: tray, recording, privacy, caffeine/airplane, headset,
13+// volume, net + bt, battery, clock (click = calendar). Clicks open the same panel tabs as always.
14+// After glyph-rice (github.com/Nebelung-cloud/glyph-rice, GPL-3.0), bar/Bar.qml.
915 PanelWindow {
1016 id: bar
1117 required property var modelData
@@ -14,8 +20,9 @@ PanelWindow {
1420 signal toggleOverlay(string name, var scr)
1521
1622 anchors { top: true; left: true; right: true }
17− implicitHeight: Theme.barHeight
18− color: Theme.barBg
23+ implicitHeight: Theme.barHeight // the pill + the gap above it; also the exclusive zone
24+ color: "transparent"
25+ mask: Region { item: pill }
1926 WlrLayershell.namespace: "aurora-bar"
2027
2128 SystemClock { id: clock; precision: SystemClock.Minutes }
@@ -33,8 +40,7 @@ PanelWindow {
3340 readonly property bool hasBat: bat !== null && bat.isPresent
3441 readonly property real batPct: hasBat ? (bat.percentage > 1 ? bat.percentage / 100 : bat.percentage) : 0
3542 readonly property bool charging: hasBat && bat.state === UPowerDeviceState.Charging
36− readonly property bool plugged: hasBat && bat.state === UPowerDeviceState.FullyCharged
37− readonly property bool batLow: hasBat && batPct <= 0.15 && !charging
43+ readonly property bool batLow: hasBat && batPct <= Settings.batLow / 100 && !charging
3844 readonly property var adapter: Bluetooth.defaultAdapter
3945
4046 // which Hyprland monitor this bar belongs to, and whether it has focus
@@ -59,39 +65,88 @@ PanelWindow {
5965 readonly property var headset: findHeadset()
6066 readonly property bool btOn: adapter !== null && adapter.enabled
6167 readonly property bool btLink: btOn && btConnected()
68+ // something records or listens: the mark's centre goes live
69+ readonly property bool live: Rec.busy || Privacy.mic || Privacy.cam || Privacy.screen
6270
63− Item {
64− anchors.fill: parent
71+ // a new toast: the mark's ring lights up for 3s (error colour if critical)
72+ property bool flash: false
73+ property bool flashCrit: false
74+ Timer { id: flashT; interval: 3000; onTriggered: bar.flash = false }
75+ Connections {
76+ target: Notifs
77+ function onArrived(n, critical) { bar.flashCrit = critical; bar.flash = true; flashT.restart() }
78+ }
79+
80+ Rectangle {
81+ id: pill
82+ x: Theme.barGap
83+ y: Theme.barGap
84+ width: parent.width - 2 * Theme.barGap
85+ height: Theme.barSize
86+ radius: height / 2
87+ color: Qt.rgba(Theme.s1.r, Theme.s1.g, Theme.s1.b, Theme.barAlpha)
88+ border.width: 1
89+ border.color: Theme.s2
6590
6691 // ---------------- left ----------------
6792 Row {
6893 anchors.left: parent.left
94+ anchors.leftMargin: Math.round(Theme.barSize * 0.25)
6995 height: parent.height
70− spacing: 10
96+ spacing: 14
97+
98+ Item {
99+ id: mark
100+ readonly property real size: Math.round(Theme.barSize * 0.55)
101+ width: size
102+ height: size
103+ anchors.verticalCenter: parent.verticalCenter
104+ Ring {
105+ anchors.fill: parent
106+ anchors.margins: 1.5
107+ n: 16
108+ dot: 2.6
109+ on: bar.flash ? (bar.flashCrit ? Theme.err : Theme.fill) : Theme.fg
110+ off: Theme.s3
111+ }
112+ Rectangle {
113+ anchors.centerIn: parent
114+ width: Math.round(mark.size * 0.32)
115+ height: width
116+ radius: width / 2
117+ color: bar.live ? Theme.live : Theme.fg
118+ }
119+ MouseArea {
120+ anchors.fill: parent
121+ anchors.margins: -5
122+ cursorShape: Qt.PointingHandCursor
123+ onClicked: bar.toggleOverlay("runner", bar.modelData)
124+ }
125+ }
71126 Workspaces { height: parent.height; monitor: bar.hmon }
72127 CatLoop { height: parent.height }
73128 }
74129
75130 // ---------------- center ----------------
76− Text {
131+ Lb {
77132 anchors.centerIn: parent
78133 width: Math.min(implicitWidth, parent.width * 0.32)
79− elide: Text.ElideRight
80134 horizontalAlignment: Text.AlignHCenter
81− readonly property string title: ToplevelManager.activeToplevel ? ToplevelManager.activeToplevel.title : ""
82− visible: bar.monFocused && title !== "" // active window is global: show it on the focused monitor only
83− text: Theme.iArch + " " + title
84− color: Theme.fg
85− font.family: Theme.font
86− font.pixelSize: Theme.fontSize
87− font.bold: true
135+ elide: Text.ElideRight
136+ readonly property var active: ToplevelManager.activeToplevel
137+ readonly property string app: active && active.appId ? String(active.appId).split(".").pop() : ""
138+ visible: bar.monFocused && active !== null && active.title !== "" // the active window is global: focused monitor only
139+ text: active ? (app !== "" ? app + " · " + active.title : active.title) : ""
140+ px: 11
141+ color: Theme.fgDim
88142 }
89143
90144 // ---------------- right ----------------
91145 Row {
92146 anchors.right: parent.right
147+ anchors.rightMargin: 6
93148 height: parent.height
94− spacing: 10
149+ spacing: 0
95150
96151 Tray { show: bar.monFocused }
97152
@@ -99,8 +154,7 @@ PanelWindow {
99154 visible: Rec.busy
100155 icon: Theme.iStop
101156 text: Rec.running ? "rec " + Theme.fmtClock(Rec.elapsed) : "select area"
102− tint: Theme.err
103− underline: Theme.err
157+ tint: Theme.live
104158 onActivated: Rec.stop()
105159 }
106160
@@ -109,23 +163,20 @@ PanelWindow {
109163 visible: bar.monFocused && Privacy.mic
110164 icon: bar.mic && bar.mic.muted ? Theme.iMicOff : Theme.iMic
111165 text: Privacy.micApps.join(", ")
112− tint: bar.mic && bar.mic.muted ? Theme.dim : Theme.err
113− underline: Theme.err
166+ tint: bar.mic && bar.mic.muted ? Theme.grey : Theme.live
114167 onActivated: if (bar.mic) bar.mic.muted = !bar.mic.muted
115168 }
116169 BarPill {
117170 visible: bar.monFocused && Privacy.cam
118171 icon: Theme.iWebcam
119172 text: Privacy.camApps.join(", ")
120− tint: Theme.err
121− underline: Theme.err
173+ tint: Theme.live
122174 }
123175 BarPill {
124176 visible: bar.monFocused && Privacy.screen
125177 icon: Theme.iCast
126178 text: Privacy.shareApps.join(", ")
127− tint: Theme.err
128− underline: Theme.err
179+ tint: Theme.live
129180 }
130181
131182 BarPill {
@@ -146,12 +197,15 @@ PanelWindow {
146197 visible: bar.audio !== null
147198 icon: Theme.volIcon(bar.audio ? bar.audio.volume : 0, bar.audio ? bar.audio.muted : true)
148199 text: (bar.audio ? Math.round(bar.audio.volume * 100) : 0) + "%"
149− + (bar.mic && bar.mic.muted ? " " + Theme.iMicOff : "")
200+ tint: bar.audio && bar.audio.muted ? Theme.grey : Theme.fg
201+ icon2: bar.mic && bar.mic.muted ? Theme.iMicOff : ""
202+ tint2: Theme.grey
150203 onActivated: button => {
151204 if (button === Qt.RightButton && bar.audio) bar.audio.muted = !bar.audio.muted
152205 else if (button === Qt.MiddleButton && bar.mic) bar.mic.muted = !bar.mic.muted
153206 else bar.togglePanel("audio", bar.modelData)
154207 }
208+ onActivated2: button => { if (bar.mic) bar.mic.muted = !bar.mic.muted }
155209 onScrolled: dir => {
156210 if (bar.audio) bar.audio.volume = Math.max(0, Math.min(1, bar.audio.volume + dir * 0.02))
157211 }
@@ -161,31 +215,78 @@ PanelWindow {
161215 BarPill {
162216 icon: Net.wired && !(Net.wifiEnabled && Net.connected !== "") ? Net.wiredIcon
163217 : (Net.wifiEnabled ? Theme.wifiIcon(Net.connected !== "" ? Net.activeSignal : 0) : Theme.iWifiOff)
164− tint: Net.portal ? Theme.err : ((Net.wired || (Net.wifiEnabled && Net.connected !== "")) ? Theme.fg : Theme.dim)
218+ tint: Net.portal ? Theme.live : ((Net.wired || (Net.wifiEnabled && Net.connected !== "")) ? Theme.fg : Theme.grey)
165219 icon2: bar.adapter === null ? "" : (!bar.btOn ? Theme.iBtOff : (bar.btLink ? Theme.iBtConn : Theme.iBt))
166− tint2: bar.btLink ? Theme.fg : Theme.dim
220+ tint2: bar.btLink ? Theme.fg : Theme.grey
167221 onActivated: bar.togglePanel("net", bar.modelData)
168222 onActivated2: bar.togglePanel("bt", bar.modelData)
169223 }
170224
225+ // battery: a capsule that fills up, the error colour when low, a bolt + breathing fill while charging
171226 BarPill {
227+ id: batt
172228 visible: bar.hasBat
173− icon: Theme.batIcon(bar.batPct, bar.charging, bar.plugged)
174− text: Math.round(bar.batPct * 100) + "%"
175− tint: bar.batLow ? Theme.err : Theme.fg
176− underline: bar.batLow ? Theme.err : Theme.accent
229+ icon: bar.charging ? Theme.iBolt : ""
177230 onActivated: bar.togglePanel("sys", bar.modelData)
231+ // breathing at 20 steps a second: an Animation would redraw the bar on every vsync while charging
232+ property real phase: 0
233+ readonly property real pulse: bar.charging ? 0.675 + 0.325 * Math.cos(phase * Math.PI / 1.1) : 1
234+ Timer {
235+ running: bar.charging && bar.visible
236+ interval: 50
237+ repeat: true
238+ onTriggered: batt.phase = (batt.phase + 0.05) % 2.2
239+ onRunningChanged: batt.phase = 0
240+ }
241+ Rectangle {
242+ anchors.verticalCenter: parent.verticalCenter
243+ width: 26
244+ height: 13
245+ radius: height / 2
246+ color: "transparent"
247+ border.width: 1.5
248+ border.color: bar.batLow ? Theme.err : Theme.grey
249+ Rectangle {
250+ x: 3
251+ anchors.verticalCenter: parent.verticalCenter
252+ width: Math.max(3, (parent.width - 6) * bar.batPct)
253+ height: parent.height - 6
254+ radius: height / 2
255+ color: bar.batLow ? Theme.err : Theme.fill
256+ opacity: batt.pulse
257+ }
258+ }
259+ Lb {
260+ anchors.verticalCenter: parent.verticalCenter
261+ text: Math.round(bar.batPct * 100)
262+ px: 11
263+ color: bar.batLow ? Theme.err : Theme.fg
264+ }
178265 }
179266
267+ // clock: Doto from bar size 40 up (Doto is unreadable smaller), Space Mono below that
180268 BarPill {
181− icon: Theme.iCal
182− text: Qt.formatDateTime(clock.date, "dd MMM yyyy")
183− onActivated: bar.toggleOverlay("cal", bar.modelData)
184− }
185− BarPill {
186− icon: Theme.iClock
187− text: Qt.formatDateTime(clock.date, "HH:mm")
188269 onActivated: bar.toggleOverlay("cal", bar.modelData)
270+ Num {
271+ visible: Theme.barSize >= 40
272+ anchors.verticalCenter: parent.verticalCenter
273+ text: Theme.hh(clock.date) + ":" + Qt.formatDateTime(clock.date, "mm")
274+ font.pixelSize: 26
275+ }
276+ Text {
277+ visible: Theme.barSize < 40
278+ anchors.verticalCenter: parent.verticalCenter
279+ text: Theme.hh(clock.date) + ":" + Qt.formatDateTime(clock.date, "mm")
280+ font.family: Theme.mono
281+ font.pixelSize: 14
282+ font.bold: true
283+ color: Theme.fg
284+ }
285+ Lb {
286+ anchors.verticalCenter: parent.verticalCenter
287+ text: Qt.locale("en_US").toString(clock.date, "ddd d")
288+ px: 10
289+ }
189290 }
190291 }
191292 }
M .config/quickshell/aurora/BarPill.qml View
@@ -1,68 +1,62 @@
11 import QtQuick
22
3−// A waybar-style block: flat, 12px padding, 1px accent underline.
3+// One block of the bar: icon, caps label, optional second icon with its own click (activated2), anything else declared
4+// inside goes after them (the battery capsule, the clock). Hover = a rounded highlight.
45 Item {
56 id: p
67 property string icon: ""
78 property string text: ""
89 property color tint: Theme.fg
9− property color underline: Theme.accent
10− // optional second icon in the same block, with its own click (activated2)
10+ property color underline: "transparent" // old style, unused
1111 property string icon2: ""
1212 property color tint2: Theme.fg
13+ default property alias extra: row.data
1314 signal activated(int button)
1415 signal activated2(int button)
1516 signal scrolled(int dir)
1617
17− implicitWidth: row.implicitWidth + 24
18− implicitHeight: parent ? parent.height : Theme.barHeight
18+ implicitWidth: row.implicitWidth + 22
19+ implicitHeight: parent ? parent.height : Theme.barSize
1920
2021 Rectangle {
2122 anchors.fill: parent
22− color: m.containsMouse ? Theme.surface : "transparent"
23− }
24− Rectangle {
25− anchors.left: parent.left
26− anchors.right: parent.right
27− anchors.bottom: parent.bottom
28− height: 1
29− color: p.underline
23+ anchors.topMargin: 5
24+ anchors.bottomMargin: 5
25+ radius: height / 2
26+ color: m.containsMouse ? Theme.s2 : "transparent"
3027 }
3128 Row {
3229 id: row
3330 anchors.centerIn: parent
34− spacing: 6
35− Text {
31+ spacing: 7
32+ Icon {
3633 visible: p.icon !== ""
34+ anchors.verticalCenter: parent.verticalCenter
3735 text: p.icon
36+ font.pixelSize: 16
3837 color: p.tint
39− font.family: Theme.font
40− font.pixelSize: Theme.fontSize + 1
41− anchors.verticalCenter: parent.verticalCenter
4238 }
43− Text {
39+ Lb {
4440 visible: p.text !== ""
41+ anchors.verticalCenter: parent.verticalCenter
4542 text: p.text
43+ px: 11
4644 color: p.tint
47− font.family: Theme.font
48− font.pixelSize: Theme.fontSize
49− font.bold: true
50− anchors.verticalCenter: parent.verticalCenter
5145 }
52− Text {
46+ Icon {
5347 id: second
5448 visible: p.icon2 !== ""
49+ anchors.verticalCenter: parent.verticalCenter
5550 text: p.icon2
51+ font.pixelSize: 16
5652 color: p.tint2
57− font.family: Theme.font
58− font.pixelSize: Theme.fontSize + 1
59− anchors.verticalCenter: parent.verticalCenter
6053 }
6154 }
6255 MouseArea {
6356 id: m
6457 anchors.fill: parent
6558 hoverEnabled: true
59+ cursorShape: Qt.PointingHandCursor
6660 acceptedButtons: Qt.LeftButton | Qt.RightButton | Qt.MiddleButton
6761 onClicked: mouse => {
6862 // split at the middle of the gap before the second icon
M .config/quickshell/aurora/CalPopup.qml View
@@ -4,19 +4,25 @@ import Quickshell
44 import Quickshell.Wayland
55 import Quickshell.Hyprland
66
7−// Month calendar under the clock pills. Monday first, ISO week numbers, scroll / arrows change month.
7+// Month calendar under the bar clock: Doto month, Monday first, ISO week numbers, today in a primary circle.
8+// Scroll / arrows change the month, up / down the year, space = back to today, Esc closes.
9+// After glyph-rice (github.com/Nebelung-cloud/glyph-rice, GPL-3.0), cal/Cal.qml.
810 PanelWindow {
911 id: win
1012 property bool opened: false
1113 signal closeRequested()
1214
13− visible: opened
15+ property real t: opened ? 1 : 0
16+ Behavior on t { NumberAnimation { duration: Theme.t; easing.type: Easing.BezierSpline; easing.bezierCurve: Theme.glide } }
17+
18+ visible: t > 0
1419 anchors { top: true; right: true }
1520 margins { top: 6; right: 8 }
16− implicitWidth: 300
17− implicitHeight: col.implicitHeight + 24
21+ implicitWidth: card.width
22+ implicitHeight: card.height + 20 // room for the slide
1823 exclusiveZone: 0
1924 color: "transparent"
25+ mask: Region { item: card }
2026 WlrLayershell.layer: WlrLayer.Overlay
2127 WlrLayershell.namespace: "aurora-calendar"
2228 WlrLayershell.keyboardFocus: WlrKeyboardFocus.OnDemand
@@ -27,7 +33,8 @@ PanelWindow {
2733 onCleared: win.closeRequested()
2834 }
2935
30− SystemClock { id: clock; precision: SystemClock.Seconds }
36+ SystemClock { id: clock; precision: SystemClock.Minutes }
37+ readonly property var en: Qt.locale("en_US")
3138
3239 property int year: 0
3340 property int month: 0 // 0..11
@@ -62,10 +69,15 @@ PanelWindow {
6269 readonly property var now: clock.date
6370
6471 Rectangle {
65− anchors.fill: parent
66− color: Theme.bgA
67− border.width: 2
68− border.color: Theme.accent
72+ id: card
73+ y: -16 * (1 - win.t)
74+ opacity: win.t
75+ width: 384
76+ height: col.implicitHeight + 44
77+ radius: 36
78+ color: Qt.rgba(Theme.s1.r, Theme.s1.g, Theme.s1.b, Theme.panelAlpha)
79+ border.width: 1
80+ border.color: Theme.s2
6981 focus: true
7082 Keys.onEscapePressed: win.closeRequested()
7183 Keys.onLeftPressed: win.shift(-1)
@@ -81,75 +93,63 @@ PanelWindow {
8193
8294 ColumnLayout {
8395 id: col
84− anchors.left: parent.left
85− anchors.right: parent.right
86− anchors.top: parent.top
87− anchors.margins: 12
88− spacing: 8
96+ x: 22
97+ y: 22
98+ width: parent.width - 44
99+ spacing: 14
89100
90− // big clock
91− Text {
92− text: Qt.formatDateTime(win.now, "HH:mm:ss")
93− color: Theme.fg
94− font.family: Theme.font
95− font.pixelSize: 28
96− font.bold: true
97− }
98− Text {
99− text: Qt.formatDateTime(win.now, "dddd, d MMMM yyyy") + " · w" + win.isoWeek(win.now)
100− color: Theme.dim
101− font.family: Theme.font
102− font.pixelSize: Theme.fontSize - 1
101+ Lb {
102+ Layout.leftMargin: 6
103+ px: 10
104+ text: win.en.toString(win.now, "dddd · d MMMM yyyy") + " · week " + win.isoWeek(win.now)
103105 }
104106
105− Rectangle { Layout.fillWidth: true; Layout.preferredHeight: 1; color: Theme.line }
106−
107107 RowLayout {
108108 Layout.fillWidth: true
109− IconBtn { icon: Theme.iPrev; implicitHeight: 24; onClicked: win.shift(-1) }
110− Text {
111− Layout.fillWidth: true
112− horizontalAlignment: Text.AlignHCenter
113− text: Qt.formatDate(new Date(win.year, win.month, 1), "MMMM yyyy").toUpperCase()
114− color: Theme.accent
115− font.family: Theme.font
116− font.pixelSize: Theme.fontSize
117− font.bold: true
118− font.letterSpacing: 1.5
109+ Layout.leftMargin: 6
110+ spacing: 12
111+ Num {
112+ text: win.en.standaloneMonthName(win.month, Locale.ShortFormat)
113+ font.pixelSize: 44
119114 MouseArea {
120115 anchors.fill: parent
121116 cursorShape: Qt.PointingHandCursor
122117 onClicked: win.today()
123118 }
124119 }
125− IconBtn { icon: Theme.iNext; implicitHeight: 24; onClicked: win.shift(1) }
120+ Lb {
121+ Layout.alignment: Qt.AlignVCenter
122+ text: win.year
123+ }
124+ Item { Layout.fillWidth: true }
125+ IconBtn { implicitHeight: 40; icon: Theme.iChevronLeft; onClicked: win.shift(-1) }
126+ IconBtn { implicitHeight: 40; icon: Theme.iChevron; onClicked: win.shift(1) }
126127 }
127128
128− GridLayout {
129+ Grid {
130+ id: grid
129131 Layout.fillWidth: true
132+ Layout.preferredWidth: 1
130133 columns: 8
131− columnSpacing: 0
132− rowSpacing: 0
134+ readonly property real cw: width / 8
133135
134136 Repeater {
135− model: ["wk", "mo", "tu", "we", "th", "fr", "sa", "su"]
136− delegate: Text {
137+ model: ["wk", "m", "t", "w", "t", "f", "s", "s"]
138+ delegate: Lb {
137139 required property var modelData
138140 required property int index
139− Layout.fillWidth: true
140− Layout.preferredHeight: 24
141+ width: grid.cw
142+ height: 28
141143 horizontalAlignment: Text.AlignHCenter
142144 verticalAlignment: Text.AlignVCenter
143145 text: modelData
144− color: index === 0 ? Theme.line : (index >= 6 ? Theme.accentDim : Theme.dim)
145− font.family: Theme.font
146− font.pixelSize: Theme.fontSize - 2
146+ px: 10
147+ color: index === 0 ? Theme.mute : Theme.grey
147148 }
148149 }
149−
150150 Repeater {
151151 model: 48
152− delegate: Rectangle {
152+ delegate: Item {
153153 id: cell
154154 required property int index
155155 readonly property bool isWeek: index % 8 === 0
@@ -158,18 +158,25 @@ PanelWindow {
158158 readonly property bool inMonth: d.getMonth() === win.month
159159 readonly property bool isToday: !isWeek && d.toDateString() === win.now.toDateString()
160160 readonly property bool weekend: (index % 8) >= 6
161− Layout.fillWidth: true
162− Layout.preferredHeight: 28
163− color: isToday ? Theme.accent : "transparent"
161+ width: grid.cw
162+ height: 40
163+ Rectangle {
164+ visible: cell.isToday
165+ anchors.centerIn: parent
166+ width: 34
167+ height: 34
168+ radius: 17
169+ color: Theme.fill
170+ }
164171 Text {
165172 anchors.centerIn: parent
166173 text: cell.isWeek ? win.isoWeek(cell.d) : cell.d.getDate()
167− color: cell.isToday ? Theme.bg
168− : cell.isWeek ? Theme.line
169− : !cell.inMonth ? Theme.surfaceHi
170− : cell.weekend ? Theme.accent : Theme.fg
171− font.family: Theme.font
172− font.pixelSize: cell.isWeek ? Theme.fontSize - 2 : Theme.fontSize
174+ color: cell.isToday ? Theme.fillFg
175+ : cell.isWeek ? Theme.mute
176+ : !cell.inMonth ? Theme.mute
177+ : cell.weekend ? Theme.grey : Theme.fg
178+ font.family: Theme.mono
179+ font.pixelSize: cell.isWeek ? 10 : 13
173180 font.bold: cell.isToday
174181 }
175182 }
M .config/quickshell/aurora/NotifPopups.qml View
@@ -1,33 +1,251 @@
11 import QtQuick
2−import QtQuick.Layouts
2+import QtQuick.Effects
33 import Quickshell
44 import Quickshell.Wayland
5+import Quickshell.Services.Notifications
56
7+// Toasts as an island at the top centre, under the bar: up to 4 cards, newest on top. Each drops in as a small pill and
8+// grows into its card; leaving, it shrinks back and the ones below slide up. Hovering holds them all, click = the app's
9+// default action, the × on hover only drops the toast (the notification stays in the history), other actions are pills.
10+// After glyph-rice's island (github.com/Nebelung-cloud/glyph-rice, GPL-3.0), glyph/Glyph.qml.
611 PanelWindow {
712 id: win
813 property bool suppressed: false // hidden while the control panel is open
14+ readonly property int cardW: 520
915
10− visible: Notifs.popups.length > 0 && !suppressed
11− anchors { top: true; right: true }
12− margins { top: 6; right: 8 }
13− implicitWidth: 360
14− implicitHeight: col.implicitHeight
16+ visible: stack.count > 0 && !suppressed
17+ anchors.top: true
18+ margins.top: 6
19+ implicitWidth: cardW
20+ implicitHeight: 4 * 160 + 20 // fixed; only the cards take input (mask)
1521 exclusiveZone: 0
1622 color: "transparent"
23+ mask: Region { item: col }
1724 WlrLayershell.layer: WlrLayer.Overlay
1825 WlrLayershell.namespace: "aurora-notifs"
1926 WlrLayershell.keyboardFocus: WlrKeyboardFocus.None
2027
21− ColumnLayout {
28+ // The island's own model: Notifs.popups is a new array on every change, which would restart every card's animation.
29+ // Entries are snapshots (a notification can close while its card animates out); refs keeps the live object.
30+ ListModel { id: stack }
31+ property var refs: ({})
32+
33+ function imgOf(n) {
34+ if (n.image && n.image !== "") return n.image
35+ if (n.appIcon && n.appIcon !== "") return Quickshell.iconPath(n.appIcon, true)
36+ return ""
37+ }
38+ function sync() {
39+ var want = {}, l = Notifs.popups
40+ for (var i = 0; i < l.length; i++) want[String(l[i].n.id)] = l[i].n
41+ for (var j = 0; j < stack.count; j++) {
42+ var e = stack.get(j)
43+ if (!e.leaving && !want[e.key]) stack.setProperty(j, "leaving", true)
44+ }
45+ for (var k in want) {
46+ var known = false
47+ for (var m = 0; m < stack.count; m++) if (stack.get(m).key === k) { known = true; break }
48+ if (known) continue
49+ var n = want[k]
50+ refs[k] = n
51+ stack.insert(0, { key: k, app: n.appName || "app", summary: n.summary || "", body: n.body || "",
52+ icon: imgOf(n), photo: !!n.image && n.image !== "",
53+ crit: n.urgency === NotificationUrgency.Critical, leaving: false })
54+ }
55+ }
56+ function forget(key) {
57+ delete refs[key]
58+ for (var i = 0; i < stack.count; i++) if (stack.get(i).key === key) { stack.remove(i); return }
59+ }
60+ Connections {
61+ target: Notifs
62+ function onPopupsChanged() { win.sync() }
63+ }
64+ Component.onCompleted: sync()
65+
66+ // hovering the island holds every toast
67+ Binding { target: Notifs; property: "hold"; value: hov.hovered }
68+
69+ Column {
2270 id: col
23− width: 360
24− spacing: 6
71+ width: win.cardW
72+ HoverHandler { id: hov }
73+
2574 Repeater {
26− model: Notifs.popups
27− delegate: NotifCard {
28− required property var modelData
29− n: modelData.n
30− popup: true
75+ model: stack
76+ delegate: Item {
77+ id: c
78+ required property int index
79+ required property string key
80+ required property string app
81+ required property string summary
82+ required property string body
83+ required property string icon
84+ required property bool photo
85+ required property bool crit
86+ required property bool leaving
87+
88+ readonly property var n: win.refs[key] || null
89+ // other actions as pills (the default one is the click); read once, the notification may close later
90+ readonly property var buttons: {
91+ var out = [], a = n ? n.actions : []
92+ for (var i = 0; i < a.length; i++) if (a[i].identifier !== "default" && a[i].text !== "") out.push(a[i])
93+ return out
94+ }
95+ readonly property var defaultAction: {
96+ var a = n ? n.actions : []
97+ for (var i = 0; i < a.length; i++) if (a[i].identifier === "default") return a[i]
98+ return null
99+ }
100+ // invoke() can close the notification: drop by key afterwards, never touch c.n again
101+ function run(action) {
102+ var k = key
103+ try { if (action) action.invoke() } catch (e) {}
104+ var nn = win.refs[k]
105+ if (nn) Notifs.dropPopup(nn)
106+ }
107+
108+ // p 0..1 linear; each phase gets its own ease-out-quart (like glide)
109+ property real p: 0
110+ Component.onCompleted: p = Qt.binding(() => leaving ? 0 : 1)
111+ Behavior on p { enabled: Theme.motion; NumberAnimation { duration: c.leaving ? 450 : 700 } }
112+ onPChanged: if (leaving && p <= 0) Qt.callLater(win.forget, key)
113+ onLeavingChanged: if (leaving && !Theme.motion) Qt.callLater(win.forget, key)
114+ function ph(a, b) { var x = Math.max(0, Math.min(1, (p - a) / (b - a))); return 1 - Math.pow(1 - x, 4) }
115+ readonly property real drop: ph(0, 0.3) // the pill drops in
116+ readonly property real grow: ph(0.25, 0.8) // and spreads into the card
117+ readonly property real full: Math.max(86, txt.implicitHeight + 32)
118+
119+ width: win.cardW
120+ height: (40 + (full - 40) * grow + 10) * drop // its slot grows and collapses with it
121+
122+ Rectangle {
123+ id: card
124+ width: 140 + (win.cardW - 140) * c.grow
125+ height: 40 + (c.full - 40) * c.grow
126+ x: (win.cardW - width) / 2
127+ y: -24 * (1 - c.drop)
128+ opacity: c.drop
129+ radius: Math.min(34, height / 2)
130+ clip: true
131+ color: Theme.s1
132+ border.width: 1
133+ border.color: c.crit ? Theme.err : Theme.grey
134+
135+ MouseArea {
136+ id: ma
137+ anchors.fill: parent
138+ hoverEnabled: true
139+ cursorShape: c.defaultAction ? Qt.PointingHandCursor : Qt.ArrowCursor
140+ onClicked: c.run(c.defaultAction)
141+ }
142+
143+ // the content at full size in the middle: text doesn't reflow while the card grows
144+ Item {
145+ anchors.centerIn: parent
146+ width: win.cardW
147+ height: c.full
148+ opacity: c.ph(0.7, 1)
149+
150+ Rectangle {
151+ id: ic
152+ x: 16
153+ anchors.verticalCenter: parent.verticalCenter
154+ width: 54
155+ height: 54
156+ radius: 27
157+ color: Theme.s2
158+ Icon { anchors.centerIn: parent; visible: !img.visible; text: Theme.iBell; font.pixelSize: 22 }
159+ Image {
160+ id: img
161+ anchors.centerIn: parent
162+ width: c.photo && Settings.appIcons === "dots" ? 54 : 30
163+ height: width
164+ visible: status === Image.Ready
165+ source: c.icon
166+ sourceSize: Qt.size(width * 2, height * 2)
167+ fillMode: Image.PreserveAspectCrop
168+ asynchronous: true
169+ layer.enabled: Settings.appIcons !== "colour"
170+ layer.effect: Settings.appIcons === "mono" ? monoFx : dotFx
171+ }
172+ Component { id: dotFx; DotMask { step: c.photo ? 3 : 2; circle: c.photo } }
173+ Component { id: monoFx; MultiEffect { saturation: -1 } }
174+ }
175+ Column {
176+ id: txt
177+ anchors.left: ic.right
178+ anchors.leftMargin: 16
179+ anchors.right: parent.right
180+ anchors.rightMargin: 48
181+ anchors.verticalCenter: parent.verticalCenter
182+ spacing: 2
183+ Lb { width: parent.width; elide: Text.ElideRight; px: 10; text: c.app + " · now" }
184+ Text {
185+ width: parent.width
186+ elide: Text.ElideRight
187+ text: c.summary
188+ font.family: Theme.ui
189+ font.pixelSize: 17
190+ font.weight: Font.DemiBold
191+ color: Theme.fg
192+ }
193+ Text {
194+ width: parent.width
195+ visible: c.body !== ""
196+ text: c.body
197+ textFormat: Text.StyledText
198+ wrapMode: Text.Wrap
199+ maximumLineCount: 2
200+ elide: Text.ElideRight
201+ font.family: Theme.ui
202+ font.pixelSize: 14
203+ color: Theme.fgDim
204+ linkColor: Theme.fill
205+ }
206+ Flow {
207+ visible: c.buttons.length > 0
208+ width: parent.width
209+ topPadding: 8
210+ spacing: 6
211+ Repeater {
212+ model: c.buttons
213+ delegate: Chip {
214+ required property var modelData
215+ text: modelData.text
216+ filled: true
217+ px: 10
218+ onClicked: c.run(modelData)
219+ }
220+ }
221+ }
222+ }
223+ // the newest one carries the live dot; on hover the dot makes room for ×
224+ Rectangle {
225+ visible: c.index === 0 && !ma.containsMouse && !closeBtn.hovered
226+ anchors.right: parent.right
227+ anchors.rightMargin: 22
228+ anchors.verticalCenter: parent.verticalCenter
229+ width: 10
230+ height: 10
231+ radius: 5
232+ color: Theme.live
233+ }
234+ IconBtn {
235+ id: closeBtn
236+ readonly property bool hovered: hh.hovered
237+ visible: ma.containsMouse || hovered
238+ anchors.right: parent.right
239+ anchors.rightMargin: 12
240+ anchors.verticalCenter: parent.verticalCenter
241+ implicitHeight: 30
242+ icon: Theme.iClose
243+ iconSize: 13
244+ onClicked: c.run(null)
245+ HoverHandler { id: hh }
246+ }
247+ }
248+ }
31249 }
32250 }
33251 }
M .config/quickshell/aurora/Notifs.qml View
@@ -8,6 +8,8 @@ import Quickshell.Services.Notifications
88 Singleton {
99 id: root
1010 property bool dnd: false
11+ property bool hold: false // the pointer is on the toasts: none expires
12+ signal arrived(var n, bool critical) // a toast was shown (the bar mark flashes)
1113
1214 // sound played on every toast (silenced by do-not-disturb, except critical ones)
1315 property bool soundEnabled: Settings.notifSound
@@ -54,6 +56,7 @@ Singleton {
5456 var next = popups.concat([{ n: n, until: Date.now() + ms }])
5557 popups = next.slice(-4)
5658 n.closed.connect(function () { root.dropPopup(n) })
59+ arrived(n, n.urgency === NotificationUrgency.Critical)
5760 }
5861
5962 NotificationServer {
@@ -82,6 +85,10 @@ Singleton {
8285 running: root.popups.length > 0
8386 repeat: true
8487 onTriggered: {
88+ if (root.hold) { // hovered: push every deadline back instead
89+ for (var i = 0; i < root.popups.length; i++) root.popups[i].until += 500
90+ return
91+ }
8592 var now = Date.now()
8693 var keep = root.popups.filter(function (p) { return p.until > now })
8794 if (keep.length !== root.popups.length) root.popups = keep
M .config/quickshell/aurora/Osd.qml View
@@ -1,11 +1,13 @@
11 import QtQuick
2+import QtQuick.Effects
23 import Quickshell
34 import Quickshell.Wayland
45 import Quickshell.Services.Pipewire
56
6−// Volume / mic / brightness popup: bottom-centre, click-through, auto-hides.
7−// Volume + mute changes are picked up natively from Pipewire (any source: keys, wpctl, panel).
8−// Brightness is pushed in via show() from the `bright` IPC call.
7+// Volume / mic / brightness on the right screen edge, like the Glyph strips on the phone: 20 segments fill bottom-up
8+// (the lit ones glow), a capsule next to them shows the icon and the value. Click-through, fades out after
9+// Settings.osdTimeout. Volume + mute come natively from Pipewire (keys, wpctl, panel); brightness is pushed in with
10+// show() from the `bright` IPC call. After glyph-rice (github.com/Nebelung-cloud/glyph-rice, GPL-3.0), glyph/Glyph.qml.
911 PanelWindow {
1012 id: win
1113 property bool suppressed: false // hidden while the control panel is open
@@ -19,16 +21,18 @@ PanelWindow {
1921 win.icon = icon
2022 win.value = value
2123 win.muted = muted
22− win.valueText = valueText !== undefined ? valueText : Math.round(value * 100) + "%"
24+ win.valueText = valueText !== undefined ? valueText : String(Math.round(value * 100))
2325 shown = true
2426 hide.restart()
2527 }
2628
27− visible: shown && !suppressed
28− anchors.bottom: true
29− margins.bottom: 80
30− implicitWidth: 280
31− implicitHeight: 40
29+ property real t: shown && !suppressed ? 1 : 0
30+ Behavior on t { NumberAnimation { duration: Theme.t; easing.type: Easing.BezierSpline; easing.bezierCurve: Theme.glide } }
31+
32+ visible: t > 0
33+ anchors.right: true // vertically centred on the right edge
34+ implicitWidth: 150
35+ implicitHeight: 520
3236 exclusiveZone: 0
3337 color: "transparent"
3438 mask: Region {}
@@ -64,46 +68,75 @@ PanelWindow {
6468 function onMutedChanged() {
6569 var a = win.source.audio
6670 if (!win.armed) return
67− win.show(a.muted ? Theme.iMicOff : Theme.iMic, a.volume, a.muted, a.muted ? "muted" : "on")
71+ win.show(a.muted ? Theme.iMicOff : Theme.iMic, a.muted ? 0 : a.volume, a.muted, a.muted ? "off" : "on")
6872 }
6973 }
7074
7175 // ---- ui ----
72− Rectangle {
76+ Item {
7377 anchors.fill: parent
74− color: Theme.bgA
75− border.width: 1
76− border.color: Theme.accent
77−
78− Row {
79− anchors.fill: parent
80− anchors.leftMargin: 12
81− anchors.rightMargin: 12
82− spacing: 10
78+ opacity: win.t
79+ transform: Translate { x: 16 * (1 - win.t) }
8380
84− Text {
85− anchors.verticalCenter: parent.verticalCenter
86− width: 20
87− text: win.icon
88− color: win.muted ? Theme.dim : Theme.fg
89− font.family: Theme.font
90− font.pixelSize: 16
91− }
92− BarSlider {
93− anchors.verticalCenter: parent.verticalCenter
94− width: parent.width - 20 - 44 - parent.spacing * 2
95− value: win.value
96− muted: win.muted
81+ // the strip: unlit segments, then the lit ones on top with the glow (the glow would outline unlit ones too)
82+ Seg {
83+ id: strip
84+ x: parent.width - 14
85+ y: 10
86+ width: 5
87+ height: parent.height - 20
88+ n: 20
89+ vertical: true
90+ f: 0
91+ }
92+ Seg {
93+ x: strip.x
94+ y: strip.y
95+ width: strip.width
96+ height: strip.height
97+ n: 20
98+ vertical: true
99+ f: win.value
100+ on: win.muted ? Theme.grey : Theme.fill
101+ off: "transparent"
102+ layer.enabled: true
103+ layer.effect: MultiEffect {
104+ shadowEnabled: true
105+ shadowColor: Theme.glow
106+ shadowBlur: 0.7
107+ blurMax: 20
108+ shadowHorizontalOffset: 0
109+ shadowVerticalOffset: 0
97110 }
98− Text {
99− anchors.verticalCenter: parent.verticalCenter
100− width: 44
101− horizontalAlignment: Text.AlignRight
102− text: win.valueText
103− color: win.muted ? Theme.dim : Theme.fg
104− font.family: Theme.font
105− font.pixelSize: Theme.fontSize
106− font.bold: true
111+ }
112+
113+ // the value next to it: icon over the number
114+ Rectangle {
115+ anchors.right: parent.right
116+ anchors.rightMargin: 32
117+ anchors.verticalCenter: parent.verticalCenter
118+ width: Math.max(58, box.implicitWidth + 24)
119+ height: box.implicitHeight + 36
120+ radius: width / 2
121+ color: Theme.s1
122+ border.width: 1
123+ border.color: Theme.s2
124+ Column {
125+ id: box
126+ anchors.centerIn: parent
127+ spacing: 12
128+ Icon {
129+ anchors.horizontalCenter: parent.horizontalCenter
130+ text: win.icon
131+ font.pixelSize: 20
132+ color: win.muted ? Theme.grey : Theme.fg
133+ }
134+ Num {
135+ anchors.horizontalCenter: parent.horizontalCenter
136+ text: win.valueText
137+ font.pixelSize: 30
138+ color: win.muted ? Theme.grey : Theme.fg
139+ }
107140 }
108141 }
109142 }
M .config/quickshell/aurora/SetAppearance.qml View
@@ -91,7 +91,7 @@ Flickable {
9191 SectionLabel { text: "sizes" }
9292 Knob { label: "font size"; from: 9; to: 18; value: Settings.fontSize; onMoved: v => Settings.fontSize = v }
9393 Knob { label: "workspace icons"; from: 8; to: 18; value: Settings.wsFontSize; onMoved: v => Settings.wsFontSize = v }
94− Knob { label: "bar height"; from: 16; to: 36; value: Settings.barHeight; onMoved: v => Settings.barHeight = v }
94+ Knob { label: "bar height"; from: 32; to: 56; value: Settings.barSize; onMoved: v => Settings.barSize = v }
9595
9696 SectionLabel { text: "transparency" }
9797 Knob { label: "bar opacity"; from: 0.3; to: 1; decimals: 2; value: Settings.barAlpha; onMoved: v => Settings.barAlpha = v }
M .config/quickshell/aurora/Settings.qml View
@@ -18,7 +18,7 @@ Singleton {
1818 idleDim: 150, idleOff: 330, idleLock: 600, idleSuspend: 0, charTone: 0, portalAutoOpen: true,
1919 chargeMode: "off", batLow: 15, batCritical: 5, batCriticalAction: "none",
2020 privacyIndicators: true, powerAuto: false, powerAc: "balanced", powerBat: "saver",
21− motion: true, clock24: true, appIcons: "dots"
21+ motion: true, clock24: true, appIcons: "dots", barSize: 40
2222 })
2323
2424 property alias fontSize: a.fontSize
@@ -54,6 +54,7 @@ Singleton {
5454 property alias motion: a.motion
5555 property alias clock24: a.clock24
5656 property alias appIcons: a.appIcons
57+ property alias barSize: a.barSize
5758
5859 function reset() {
5960 for (var k in defaults) a[k] = defaults[k]
@@ -111,6 +112,7 @@ Singleton {
111112 property bool motion: true // shell animations (Theme.t)
112113 property bool clock24: true
113114 property string appIcons: "dots" // dots | mono | colour: how app icons are drawn
115+ property int barSize: 40 // height of the bar pill (Doto clock from 40 up)
114116 }
115117 }
116118 // first run: create the file once the directory exists
M .config/quickshell/aurora/Theme.qml View
@@ -19,7 +19,9 @@ Singleton {
1919 readonly property int fontSize: Settings.fontSize
2020 readonly property int wsFontSize: Settings.wsFontSize // workspace icons only; everything else uses fontSize
2121 readonly property real panelAlpha: Settings.panelAlpha
22− readonly property int barHeight: Settings.barHeight
22+ readonly property int barSize: Math.max(32, Settings.barSize) // the bar pill
23+ readonly property int barGap: 6 // pill to the screen edge
24+ readonly property int barHeight: barSize + barGap // what the bar reserves at the top
2325 readonly property real barAlpha: Settings.barAlpha
2426
2527 // ---- motion: ease-out-quart without overshoot (glyph's "glide"); Settings.motion off = instant ----
M .config/quickshell/aurora/Tray.qml View
@@ -1,43 +1,40 @@
11 import QtQuick
2+import QtQuick.Effects
23 import Quickshell
34 import Quickshell.Services.SystemTray
45
6+// Tray icons in the bar; monochrome unless Settings.appIcons is "colour" (dots are too coarse at this size).
57 Item {
68 id: tray
79 property bool show: true
810 visible: show && SystemTray.items.values.length > 0
9− implicitWidth: row.implicitWidth + 24
10− implicitHeight: parent ? parent.height : Theme.barHeight
11+ implicitWidth: row.implicitWidth + 22
12+ implicitHeight: parent ? parent.height : Theme.barSize
1113
12− Rectangle {
13− anchors.left: parent.left
14− anchors.right: parent.right
15− anchors.bottom: parent.bottom
16− height: 1
17− color: Theme.dim
18− }
1914 Row {
2015 id: row
2116 anchors.centerIn: parent
22− spacing: 10
17+ spacing: 12
2318 Repeater {
2419 model: SystemTray.items
2520 delegate: Item {
2621 id: it
2722 required property var modelData
28− width: 14
29− height: 14
23+ width: 16
24+ height: 16
3025 anchors.verticalCenter: parent.verticalCenter
3126
3227 function openMenu() {
33− var p = it.mapToItem(null, 0, it.height + 4)
28+ var p = it.mapToItem(null, 0, it.height + 10)
3429 modelData.display(QsWindow.window, p.x, p.y)
3530 }
3631 Image {
3732 anchors.fill: parent
3833 source: it.modelData.icon
39− sourceSize: Qt.size(28, 28)
34+ sourceSize: Qt.size(32, 32)
4035 smooth: true
36+ layer.enabled: Settings.appIcons !== "colour"
37+ layer.effect: MultiEffect { saturation: -1; brightness: 0.1 }
4138 }
4239 MouseArea {
4340 anchors.fill: parent
M .config/quickshell/aurora/Workspaces.qml View
@@ -1,13 +1,14 @@
11 import QtQuick
22 import Quickshell.Hyprland
33
4−// Per-monitor workspaces, dwm / split-monitor-workspaces style.
5−// Each monitor owns a block of 10 ids (monitor 1: 1-10, monitor 2: 11-20, ...).
6−// The block is derived from the monitor's own active workspace, so it works with or
7−// without the plugin. Icons repeat every 10, like your waybar format-icons.
4+// This monitor's 10 workspaces as dots (split-monitor-workspaces: monitor 1 owns 1-10, monitor 2 11-20, ...; the block
5+// comes from the monitor's own active workspace, so it works without the plugin too).
6+// Active = a wide pill (primary on the focused monitor, grey on the others), occupied = grey dot, empty = dim dot,
7+// urgent = the live colour. Click = go there, wheel = the next / previous occupied one.
8+// After glyph-rice (github.com/Nebelung-cloud/glyph-rice, GPL-3.0), bar/Bar.qml.
89 Row {
910 id: ws
10− spacing: 0
11+ spacing: 6
1112
1213 property var monitor: null // HyprlandMonitor of the bar this sits in
1314
@@ -40,36 +41,31 @@ Row {
4041 readonly property bool active: ws.activeWs !== null && ws.activeWs.id === modelData
4142 readonly property bool occupied: obj !== null && obj.toplevels.values.length > 0
4243 readonly property bool urgent: obj !== null && obj.urgent
43− // active on the focused monitor = filled; active on another monitor = accent text + thick underline
44− readonly property bool lit: (active && ws.monFocused) || m.containsMouse
45− readonly property bool dimActive: active && !ws.monFocused && !m.containsMouse
4644
47− width: 30
45+ width: dot.width
4846 height: ws.height
4947
5048 Rectangle {
51− anchors.fill: parent
52− color: b.lit ? Theme.accent : "transparent"
53− }
54− Rectangle { // occupied marker (1px), or active-on-unfocused-monitor marker (2px)
55− visible: (b.occupied && !b.lit) || b.dimActive
56− anchors.left: parent.left
57− anchors.right: parent.right
58− anchors.bottom: parent.bottom
59− height: b.dimActive ? 2 : 1
60− color: b.dimActive ? Theme.accent : Theme.cursorC
61− }
62− Text {
63− anchors.centerIn: parent
64− text: Theme.wsIcon(b.modelData)
65− color: b.lit ? Theme.bg : (b.dimActive ? Theme.accent : (b.urgent ? Theme.err : Theme.fg))
66− opacity: (b.occupied || b.active || b.lit || b.urgent) ? 1 : 0.4
67− font.family: Theme.font
68− font.pixelSize: Theme.wsFontSize
49+ id: dot
50+ anchors.verticalCenter: parent.verticalCenter
51+ width: b.active ? 26 : 8
52+ height: 8
53+ radius: 4
54+ color: b.urgent && !b.active ? Theme.live
55+ : b.active ? (ws.monFocused ? Theme.fill : Theme.grey)
56+ : m.containsMouse ? Theme.fg
57+ : b.occupied ? Theme.grey : Theme.s3
58+ Behavior on width {
59+ enabled: Theme.motion
60+ NumberAnimation { duration: Theme.t; easing.type: Easing.BezierSpline; easing.bezierCurve: Theme.glide }
61+ }
62+ Behavior on color { enabled: Theme.motion; ColorAnimation { duration: Theme.t } }
6963 }
7064 MouseArea {
7165 id: m
7266 anchors.fill: parent
67+ anchors.leftMargin: -3
68+ anchors.rightMargin: -3
7369 hoverEnabled: true
7470 cursorShape: Qt.PointingHandCursor
7571 onClicked: Hypr.workspace(b.modelData)
M .config/quickshell/aurora/shell.qml View
@@ -1,3 +1,5 @@
1+//@ pragma UseQApplication
2+// ^ tray menus (SystemTray display()) are platform menus: they need a QApplication
13 //@ pragma IconTheme Papirus-Dark
24 // ^ same as gtk-3.0: notify-send -i names (drive-removable-media, network-wireless, ...) resolve through it
35 import QtQuick