me like nix
1import QtQuick
2import QtQuick.Layouts
3import Quickshell
4import Quickshell.Wayland
5import "../../../config" as Config
6import "../../../components"
7import "../../../services" as Services
8
9PopupWindow {
10 id: dashPopout
11
12 property bool show: false
13 property var parentWindow
14 property real anchorY: 0
15 signal close()
16
17 visible: show || contentRect.opacity > 0
18 anchor.window: parentWindow
19 anchor.onAnchoring: {
20 anchor.rect.x = parentWindow.width + 8
21 anchor.rect.y = Math.max(0, anchorY - implicitHeight / 2)
22 }
23
24 implicitWidth: 280
25 implicitHeight: dashContent.implicitHeight + 32
26 color: "transparent"
27
28 onShowChanged: {
29 if (show) { contentRect._opening = true; fadeIn.start(); resetMonth() }
30 else { fadeIn.stop(); contentRect._opening = false; contentRect.opacity = 0 }
31 }
32 Timer { id: fadeIn; interval: 16; onTriggered: contentRect.opacity = 1 }
33
34 property int calYear: new Date().getFullYear()
35 property int calMonth: new Date().getMonth()
36
37 function calendarDays() {
38 var firstDay = new Date(calYear, calMonth, 1).getDay()
39 var daysInMonth = new Date(calYear, calMonth + 1, 0).getDate()
40 var prevDays = new Date(calYear, calMonth, 0).getDate()
41 var today = new Date()
42 var isCurrentMonth = (calYear === today.getFullYear() && calMonth === today.getMonth())
43 var days = []
44 for (var i = 0; i < 42; i++) {
45 var dayNum = i - firstDay + 1
46 if (dayNum < 1)
47 days.push({ day: prevDays + dayNum, inMonth: false, isToday: false })
48 else if (dayNum > daysInMonth)
49 days.push({ day: dayNum - daysInMonth, inMonth: false, isToday: false })
50 else
51 days.push({ day: dayNum, inMonth: true, isToday: isCurrentMonth && dayNum === today.getDate() })
52 }
53 return days
54 }
55
56 function prevMonth() {
57 if (calMonth === 0) { calMonth = 11; calYear-- }
58 else calMonth--
59 calModel = calendarDays()
60 }
61
62 function nextMonth() {
63 if (calMonth === 11) { calMonth = 0; calYear++ }
64 else calMonth++
65 calModel = calendarDays()
66 }
67
68 function resetMonth() {
69 var now = new Date()
70 calYear = now.getFullYear()
71 calMonth = now.getMonth()
72 calModel = calendarDays()
73 }
74
75 property var calModel: calendarDays()
76
77 Rectangle {
78 id: contentRect
79 anchors.fill: parent
80 color: Config.Colours.base
81 radius: Config.Appearance.rounding.large
82 border.width: 1
83 border.color: Config.Colours.surface0
84 opacity: 0
85 property bool _opening: false
86 Behavior on opacity {
87 Anim {
88 duration: contentRect._opening ? Config.Appearance.anim.durations.normal : Config.Appearance.anim.durations.small
89 easing.bezierCurve: contentRect._opening ? Config.Appearance.anim.curves.standardDecel : Config.Appearance.anim.curves.standardAccel
90 }
91 }
92
93 ColumnLayout {
94 id: dashContent
95 anchors.fill: parent
96 anchors.margins: 16
97 spacing: 12
98
99 // Time + Date
100 ColumnLayout {
101 Layout.fillWidth: true
102 spacing: 2
103
104 Text {
105 id: dashTime
106 color: Config.Colours.blue
107 font.family: Config.Appearance.font.family
108 font.pixelSize: 32
109 font.bold: true
110 text: Qt.formatDateTime(new Date(), "HH:mm")
111 Timer {
112 interval: 1000
113 running: dashPopout.show
114 repeat: true
115 onTriggered: dashTime.text = Qt.formatDateTime(new Date(), "HH:mm")
116 }
117 }
118
119 Text {
120 color: Config.Colours.subtext0
121 font.family: Config.Appearance.font.family
122 font.pixelSize: Config.Appearance.font.size.small
123 text: Qt.formatDateTime(new Date(), "dddd, MMMM d")
124 }
125 }
126
127 Rectangle { Layout.fillWidth: true; height: 1; color: Config.Colours.surface1 }
128
129 // Calendar
130 Column {
131 Layout.fillWidth: true
132 spacing: 4
133
134 RowLayout {
135 width: parent.width
136
137 Text {
138 color: Config.Colours.overlay0
139 font.family: Config.Appearance.font.family
140 font.pixelSize: 14
141 text: "\uf053"
142 MouseArea { anchors.fill: parent; cursorShape: Qt.PointingHandCursor; onClicked: dashPopout.prevMonth() }
143 }
144 Item { Layout.fillWidth: true }
145 Text {
146 color: Config.Colours.text
147 font.family: Config.Appearance.font.family
148 font.pixelSize: Config.Appearance.font.size.normal
149 font.bold: true
150 text: new Date(dashPopout.calYear, dashPopout.calMonth, 1).toLocaleDateString(Qt.locale(), "MMMM yyyy")
151 MouseArea { anchors.fill: parent; cursorShape: Qt.PointingHandCursor; onClicked: dashPopout.resetMonth() }
152 }
153 Item { Layout.fillWidth: true }
154 Text {
155 color: Config.Colours.overlay0
156 font.family: Config.Appearance.font.family
157 font.pixelSize: 14
158 text: "\uf054"
159 MouseArea { anchors.fill: parent; cursorShape: Qt.PointingHandCursor; onClicked: dashPopout.nextMonth() }
160 }
161 }
162
163 Row {
164 spacing: 0
165 Repeater {
166 model: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa"]
167 delegate: Text {
168 required property string modelData
169 width: (dashContent.width - 32) / 7
170 horizontalAlignment: Text.AlignHCenter
171 color: Config.Colours.overlay0
172 font.family: Config.Appearance.font.family
173 font.pixelSize: 10
174 text: modelData
175 }
176 }
177 }
178
179 Grid {
180 columns: 7
181 rowSpacing: 2
182
183 Repeater {
184 model: dashPopout.calModel
185 delegate: Item {
186 required property var modelData
187 width: (dashContent.width - 32) / 7
188 height: 24
189
190 Rectangle {
191 anchors.centerIn: parent
192 width: 22; height: 22; radius: 11
193 color: modelData.isToday ? Config.Colours.blue : "transparent"
194 }
195
196 Text {
197 anchors.centerIn: parent
198 color: modelData.isToday ? Config.Colours.crust
199 : (modelData.inMonth ? Config.Colours.text : Config.Colours.overlay0)
200 font.family: Config.Appearance.font.family
201 font.pixelSize: 11
202 font.bold: modelData.isToday
203 text: modelData.day
204 }
205 }
206 }
207 }
208 }
209
210 Rectangle {
211 Layout.fillWidth: true; height: 1; color: Config.Colours.surface1
212 visible: Services.Weather.weather !== ""
213 }
214
215 // Weather
216 RowLayout {
217 Layout.fillWidth: true
218 spacing: 8
219 visible: Services.Weather.weather !== ""
220
221 Text {
222 color: Config.Colours.yellow
223 font.family: Config.Appearance.font.family
224 font.pixelSize: 16
225 text: "\uf0eb"
226 }
227 Text {
228 Layout.fillWidth: true
229 color: Config.Colours.text
230 font.family: Config.Appearance.font.family
231 font.pixelSize: Config.Appearance.font.size.normal
232 text: Services.Weather.weather
233 wrapMode: Text.WordWrap
234 }
235 }
236
237 Rectangle { Layout.fillWidth: true; height: 1; color: Config.Colours.surface1 }
238
239 // System
240 ColumnLayout {
241 Layout.fillWidth: true
242 spacing: 6
243
244 Text {
245 color: Config.Colours.text
246 font.family: Config.Appearance.font.family
247 font.pixelSize: Config.Appearance.font.size.normal
248 font.bold: true
249 text: "System"
250 }
251
252 Repeater {
253 model: {
254 var items = [
255 { icon: "\uf2db", label: "CPU", value: Services.SystemUsage.cpuUsage + "%", color: Config.Colours.peach },
256 { icon: "\uefc5", label: "Memory", value: Services.SystemUsage.memUsage + "%", color: Config.Colours.mauve },
257 { icon: "\uf2c9", label: "Temp", value: Services.SystemUsage.temperature + "\u00b0C", color: Config.Colours.red }
258 ]
259 if (Services.Battery.hasBattery)
260 items.push({ icon: "\uf241", label: "Battery", value: Services.Battery.percent + "%", color: Config.Colours.green })
261 return items
262 }
263 delegate: RowLayout {
264 required property var modelData
265 Layout.fillWidth: true
266 Text { color: modelData.color; font.family: Config.Appearance.font.family; font.pixelSize: 12; text: modelData.icon }
267 Text { color: Config.Colours.subtext0; font.family: Config.Appearance.font.family; font.pixelSize: 12; text: modelData.label }
268 Item { Layout.fillWidth: true }
269 Text { color: Config.Colours.text; font.family: Config.Appearance.font.family; font.pixelSize: 12; text: modelData.value }
270 }
271 }
272 }
273 }
274
275 Keys.onEscapePressed: dashPopout.close()
276 }
277
278 MouseArea { anchors.fill: parent; z: -1; onClicked: dashPopout.close() }
279}