Files
dotfiles/roles/quickshell/files/bar/CalendarContent.qml
2026-04-14 18:13:39 +02:00

140 lines
4.9 KiB
QML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import QtQuick
import "../components"
// Calendar grid a plain Item so it can live inside an expanding section border.
Item {
id: root
property var now: new Date()
property int viewYear: now.getFullYear()
property int viewMonth: 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: now.getFullYear()
readonly property int todayMonth: now.getMonth()
readonly property int todayDay: now.getDate()
// All widths derived from this constant — never from parent.width —
// to avoid Column polish loops when the popup is wider than the grid.
readonly property int cellW: 28
readonly property int cellGap: 2
readonly property int gridW: 7 * cellW + 6 * cellGap // 208
implicitWidth: gridW + 24
implicitHeight: calLayout.implicitHeight + 16
Column {
id: calLayout
// Centre the fixed-width grid inside the (potentially wider) popup.
// No left+right anchors → implicitWidth stays at gridW, no resize loop.
anchors { top: parent.top; topMargin: 8; horizontalCenter: parent.horizontalCenter }
spacing: 6
// Month navigation — all child widths are explicit constants
Row {
spacing: 0
Text {
text: ""
color: Theme.text
font.pixelSize: 16
width: 20
horizontalAlignment: Text.AlignHCenter
MouseArea {
anchors.fill: parent
cursorShape: Qt.PointingHandCursor
onClicked: {
if (root.viewMonth === 0) { root.viewMonth = 11; root.viewYear-- }
else root.viewMonth--
}
}
}
Text {
text: root.monthNames[root.viewMonth] + " " + root.viewYear
color: Theme.text
font.pixelSize: 13
font.bold: true
width: root.gridW - 40 // fixed constant, not parent.width
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 (root.viewMonth === 11) { root.viewMonth = 0; root.viewYear++ }
else root.viewMonth++
}
}
}
}
// Weekday headers
Row {
spacing: root.cellGap
Repeater {
model: ["Mo","Tu","We","Th","Fr","Sa","Su"]
Text {
text: modelData
color: Theme.textDim
font.pixelSize: 10
width: root.cellW
horizontalAlignment: Text.AlignHCenter
}
}
}
// Day grid
Grid {
columns: 7
spacing: root.cellGap
Repeater {
model: root.totalCells
delegate: Item {
width: root.cellW
height: 22
readonly property int dayNum: index - root.startOffset + 1
readonly property bool valid:
index >= root.startOffset &&
index < root.startOffset + root.daysInMonth
readonly property bool isToday:
valid &&
root.viewYear === root.todayYear &&
root.viewMonth === root.todayMonth &&
dayNum === root.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
}
}
}
}
}
}