import Quickshell import QtQuick import "../components" Item { id: root implicitWidth: timeLabel.implicitWidth + 10 implicitHeight: 24 property var now: new Date() Timer { interval: 1000 running: true repeat: true onTriggered: root.now = new Date() } readonly property string display: { const d = now const days = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"] const h = String(d.getHours()).padStart(2, "0") const m = String(d.getMinutes()).padStart(2, "0") const s = String(d.getSeconds()).padStart(2, "0") return days[d.getDay()] + " " + h + ":" + m + ":" + s } Text { id: timeLabel anchors.centerIn: parent text: root.display color: Theme.text font.pixelSize: 12 font.family: "JetBrainsMono Nerd Font Mono" } MouseArea { anchors.fill: parent cursorShape: Qt.PointingHandCursor onClicked: calPopup.visible = !calPopup.visible } // --------------- Calendar popup --------------- PopupWindow { id: calPopup visible: false anchor.item: root anchor.edges: Edges.Bottom anchor.gravity: Edges.Bottom // calendar state property int viewYear: root.now.getFullYear() property int viewMonth: root.now.getMonth() // 0-based readonly property var monthNames: [ "January","February","March","April","May","June", "July","August","September","October","November","December" ] readonly property int daysInMonth: new Date(viewYear, viewMonth + 1, 0).getDate() // first weekday of month: Mon=0 … Sun=6 readonly property int startOffset: (new Date(viewYear, viewMonth, 1).getDay() + 6) % 7 readonly property int totalCells: Math.ceil((startOffset + daysInMonth) / 7) * 7 readonly property int todayYear: root.now.getFullYear() readonly property int todayMonth: root.now.getMonth() readonly property int todayDay: root.now.getDate() implicitWidth: calBg.implicitWidth implicitHeight: calBg.implicitHeight Rectangle { id: calBg anchors.fill: parent color: Theme.bg border.color: Theme.border border.width: Theme.borderWidth radius: Theme.radius implicitWidth: calLayout.implicitWidth + 24 implicitHeight: calLayout.implicitHeight + 24 Column { id: calLayout anchors { fill: parent; margins: 12 } spacing: 6 // Month navigation Row { width: parent.width spacing: 0 Text { text: "‹" color: Theme.text font.pixelSize: 16 width: 20 horizontalAlignment: Text.AlignHCenter MouseArea { anchors.fill: parent cursorShape: Qt.PointingHandCursor onClicked: { if (calPopup.viewMonth === 0) { calPopup.viewMonth = 11 calPopup.viewYear-- } else { calPopup.viewMonth-- } } } } Text { text: calPopup.monthNames[calPopup.viewMonth] + " " + calPopup.viewYear color: Theme.text font.pixelSize: 13 font.bold: true // fill remaining space between arrows width: parent.width - 40 horizontalAlignment: Text.AlignHCenter } Text { text: "›" color: Theme.text font.pixelSize: 16 width: 20 horizontalAlignment: Text.AlignHCenter MouseArea { anchors.fill: parent cursorShape: Qt.PointingHandCursor onClicked: { if (calPopup.viewMonth === 11) { calPopup.viewMonth = 0 calPopup.viewYear++ } else { calPopup.viewMonth++ } } } } } // Weekday headers Row { spacing: 2 Repeater { model: ["Mo","Tu","We","Th","Fr","Sa","Su"] Text { text: modelData color: Theme.textDim font.pixelSize: 10 width: 28 horizontalAlignment: Text.AlignHCenter } } } // Day grid Grid { columns: 7 spacing: 2 Repeater { model: calPopup.totalCells delegate: Item { width: 28 height: 22 readonly property int dayNum: index - calPopup.startOffset + 1 readonly property bool valid: index >= calPopup.startOffset && index < calPopup.startOffset + calPopup.daysInMonth readonly property bool isToday: valid && calPopup.viewYear === calPopup.todayYear && calPopup.viewMonth === calPopup.todayMonth && dayNum === calPopup.todayDay Rectangle { anchors.fill: parent radius: 3 color: isToday ? Theme.accent : "transparent" visible: isToday } Text { anchors.centerIn: parent text: parent.valid ? String(parent.dayNum) : "" color: parent.isToday ? Theme.text : Theme.textDim font.pixelSize: 11 font.bold: parent.isToday } } } } } } } }