add ClockApplet with locale-aware calendar grid, refactor ClockModule with hover+pin
This commit is contained in:
parent
0e9c1723f2
commit
472b4e62ab
3 changed files with 198 additions and 4 deletions
148
shell/applets/ClockApplet.qml
Normal file
148
shell/applets/ClockApplet.qml
Normal file
|
|
@ -0,0 +1,148 @@
|
|||
import QtQuick
|
||||
import "../services" as S
|
||||
|
||||
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: S.Theme.fontSize
|
||||
font.family: S.Theme.fontFamily
|
||||
font.bold: true
|
||||
}
|
||||
|
||||
Text {
|
||||
anchors.right: parent.right
|
||||
anchors.rightMargin: 12
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
text: "W" + root._weekNumber(root.currentDate)
|
||||
color: S.Theme.base04
|
||||
font.pixelSize: S.Theme.fontSize - 2
|
||||
font.family: S.Theme.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: S.Theme.base04
|
||||
font.pixelSize: S.Theme.fontSize - 3
|
||||
font.family: S.Theme.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 ? S.Theme.base00 : modelData.isCurrentMonth ? S.Theme.base05 : S.Theme.base03
|
||||
font.pixelSize: S.Theme.fontSize - 1
|
||||
font.family: S.Theme.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: S.Theme.base04
|
||||
font.pixelSize: S.Theme.fontSize - 2
|
||||
font.family: S.Theme.fontFamily
|
||||
}
|
||||
|
||||
Item {
|
||||
width: 1
|
||||
height: 4
|
||||
}
|
||||
}
|
||||
|
|
@ -2,6 +2,7 @@ module applets
|
|||
# keep-sorted start
|
||||
BacklightApplet 1.0 BacklightApplet.qml
|
||||
BatteryApplet 1.0 BatteryApplet.qml
|
||||
ClockApplet 1.0 ClockApplet.qml
|
||||
CpuApplet 1.0 CpuApplet.qml
|
||||
DiskApplet 1.0 DiskApplet.qml
|
||||
GpuApplet 1.0 GpuApplet.qml
|
||||
|
|
|
|||
|
|
@ -2,14 +2,59 @@ import QtQuick
|
|||
import Quickshell
|
||||
import "." as M
|
||||
import "../services" as S
|
||||
import "../applets" as C
|
||||
|
||||
M.BarSection {
|
||||
id: root
|
||||
spacing: S.Theme.moduleSpacing
|
||||
tooltip: ""
|
||||
|
||||
M.BarLabel {
|
||||
SystemClock {
|
||||
id: clock
|
||||
precision: SystemClock.Seconds
|
||||
}
|
||||
|
||||
property bool _pinned: false
|
||||
readonly property bool _anyHover: root._hovered || hoverPanel.panelHovered
|
||||
readonly property bool _showPanel: _anyHover || _pinned
|
||||
|
||||
on_AnyHoverChanged: {
|
||||
if (_anyHover)
|
||||
_unpinTimer.stop();
|
||||
else if (_pinned)
|
||||
_unpinTimer.start();
|
||||
}
|
||||
|
||||
Timer {
|
||||
id: _unpinTimer
|
||||
interval: 500
|
||||
onTriggered: root._pinned = false
|
||||
}
|
||||
|
||||
M.BarLabel {
|
||||
font.pixelSize: S.Theme.fontSize + 1
|
||||
label: Qt.formatDateTime(clock.date, "ddd, dd. MMM HH:mm")
|
||||
tooltip: Qt.formatDateTime(clock.date, "dddd, dd. MMMM yyyy\nHH:mm:ss")
|
||||
minText: "Wed, 00. Sep 00:00"
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
TapHandler {
|
||||
onTapped: root._pinned = !root._pinned
|
||||
}
|
||||
}
|
||||
|
||||
M.HoverPanel {
|
||||
id: hoverPanel
|
||||
showPanel: root._showPanel
|
||||
screen: QsWindow.window?.screen ?? null
|
||||
anchorItem: root
|
||||
accentColor: root.accentColor
|
||||
panelNamespace: "nova-clock"
|
||||
panelTitle: Qt.formatTime(clock.date, "HH:mm:ss")
|
||||
contentWidth: 220
|
||||
|
||||
C.ClockApplet {
|
||||
width: hoverPanel.contentWidth
|
||||
accentColor: root.accentColor
|
||||
currentDate: clock.date
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue