import QtQuick import "../services" as S import NovaStats as NS Column { id: root required property color accentColor required property date currentDate readonly property var _locale: Qt.locale() readonly property int _year: currentDate.getFullYear() readonly property int _month: currentDate.getMonth() readonly property int _day: currentDate.getDate() readonly property int _firstDayOfWeek: _locale.firstDayOfWeek // Week number (ISO 8601) function _weekNumber(d) { const tmp = new Date(d.getTime()); tmp.setHours(0, 0, 0, 0); tmp.setDate(tmp.getDate() + 3 - (tmp.getDay() + 6) % 7); const jan4 = new Date(tmp.getFullYear(), 0, 4); return 1 + Math.round(((tmp.getTime() - jan4.getTime()) / 86400000 - 3 + (jan4.getDay() + 6) % 7) / 7); } // Build 6x7 grid of day numbers for the current month view readonly property var _calendarDays: { const first = new Date(_year, _month, 1); const firstDow = first.getDay(); // Offset: how many days from previous month to show let offset = (firstDow - _firstDayOfWeek + 7) % 7; const startDate = new Date(_year, _month, 1 - offset); const days = []; for (let i = 0; i < 42; i++) { const d = new Date(startDate.getTime() + i * 86400000); days.push({ day: d.getDate(), month: d.getMonth(), year: d.getFullYear(), isCurrentMonth: d.getMonth() === _month, isToday: d.getDate() === _day && d.getMonth() === _month && d.getFullYear() === _year }); } return days; } // Weekday header names (short, locale-aware) readonly property var _dayNames: { const names = []; for (let i = 0; i < 7; i++) { const idx = (_firstDayOfWeek + i) % 7; names.push(_locale.dayName(idx, Locale.NarrowFormat)); } return names; } // Date header Item { width: parent.width height: 28 Text { anchors.left: parent.left anchors.leftMargin: 12 anchors.verticalCenter: parent.verticalCenter text: root._locale.standaloneMonthName(root._month, Locale.LongFormat) + " " + root._year color: root.accentColor font.pixelSize: NS.ThemeService.fontSize font.family: NS.ThemeService.fontFamily font.bold: true } Text { anchors.right: parent.right anchors.rightMargin: 12 anchors.verticalCenter: parent.verticalCenter text: "W" + root._weekNumber(root.currentDate) color: NS.ThemeService.base04 font.pixelSize: NS.ThemeService.fontSize - 2 font.family: NS.ThemeService.fontFamily } } // Day-of-week headers Row { anchors.horizontalCenter: parent.horizontalCenter Repeater { model: root._dayNames Text { required property string modelData width: Math.floor((root.width - 24) / 7) height: 18 horizontalAlignment: Text.AlignHCenter text: modelData color: NS.ThemeService.base04 font.pixelSize: NS.ThemeService.fontSize - 3 font.family: NS.ThemeService.fontFamily font.bold: true } } } // Calendar grid (6 rows x 7 cols) Grid { anchors.horizontalCenter: parent.horizontalCenter columns: 7 Repeater { model: root._calendarDays Item { required property var modelData width: Math.floor((root.width - 24) / 7) height: Math.floor((root.width - 24) / 7) Rectangle { anchors.centerIn: parent width: Math.min(parent.width, parent.height) - 4 height: width radius: width / 2 color: modelData.isToday ? root.accentColor : "transparent" } Text { anchors.centerIn: parent text: modelData.day color: modelData.isToday ? NS.ThemeService.base00 : modelData.isCurrentMonth ? NS.ThemeService.base05 : NS.ThemeService.base03 font.pixelSize: NS.ThemeService.fontSize - 1 font.family: NS.ThemeService.fontFamily font.bold: modelData.isToday } } } } // Full date line Text { width: parent.width - 24 anchors.horizontalCenter: parent.horizontalCenter horizontalAlignment: Text.AlignHCenter text: root.currentDate.toLocaleDateString(root._locale, Locale.LongFormat) color: NS.ThemeService.base04 font.pixelSize: NS.ThemeService.fontSize - 2 font.family: NS.ThemeService.fontFamily } Item { width: 1 height: 4 } }