Add a calendar popup to the clock

Clicking the clock reveals a month grid with ISO week numbers, a year
progress meter, and month stepping. Right click walks the common label
formats and writes the chosen one back to shell.json, so the bar shows
what the config stores. The week start toggles from the grid's "W"
heading and persists as weekStartDay, defaulting to the locale's own
first day.

Rich popup widgets live in their own plugin directories, so the clock
moves out of bar/widgets/ into panels/clock/. The id is unchanged, so
existing layouts and centerAnchor keep working.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
David Heinemeier Hansson
2026-07-26 19:10:06 -07:00
co-authored by Claude Opus 5
parent c2610c3788
commit e2d655d265
9 changed files with 1113 additions and 98 deletions
@@ -1,20 +0,0 @@
{
"schemaVersion": 1,
"id": "omarchy.clock",
"name": "Clock",
"version": "1.0.0",
"author": "Omarchy",
"description": "Day/time label; click to toggle alternate format",
"kinds": [
"bar-widget"
],
"entryPoints": {
"barWidget": "Clock.qml"
},
"barWidget": {
"displayName": "Clock",
"description": "Day/time label; click to toggle alternate format",
"category": "Time",
"allowMultiple": false
}
}
-92
View File
@@ -1,92 +0,0 @@
import QtQuick
import Quickshell
import Quickshell.Io
import qs.Commons
import qs.Ui
BarWidget {
id: root
moduleName: "omarchy.clock"
property bool alt: false
property date displayDate: clock.date
readonly property string activeFormat: alt
? (vertical ? setting("verticalFormatAlt", "dd\nMMM\n'W'ww\n''yy") : setting("formatAlt", "d MMMM 'W'ww yyyy"))
: (vertical ? setting("verticalFormat", "HH\n—\nmm") : setting("format", "dddd HH:mm"))
readonly property string displayText: formatted(displayDate)
readonly property var verticalLines: displayText.split("\n")
function refresh() {
displayDate = new Date()
}
function isoWeek(date) {
var d = new Date(Date.UTC(date.getFullYear(), date.getMonth(), date.getDate()))
var day = d.getUTCDay() || 7
d.setUTCDate(d.getUTCDate() + 4 - day)
var yearStart = new Date(Date.UTC(d.getUTCFullYear(), 0, 1))
return Math.ceil(((d - yearStart) / 86400000 + 1) / 7)
}
function isoWeekLiteral(date) {
var week = isoWeek(date)
return (week < 10 ? "0" : "") + week
}
function formatted(date) {
return Qt.formatDateTime(date, activeFormat.replace(/ww/g, isoWeekLiteral(date)))
}
implicitWidth: button.implicitWidth
implicitHeight: button.implicitHeight
SystemClock {
id: clock
precision: SystemClock.Minutes
onDateChanged: root.displayDate = date
}
IpcHandler {
target: "omarchy.clock"
function refresh(): void { root.broadcast("refresh") }
}
WidgetButton {
id: button
anchors.fill: parent
bar: root.bar
text: root.vertical ? "" : root.displayText
labelVisible: !root.vertical
hasVisualContent: root.vertical ? root.verticalLines.length > 0 : text !== ""
fixedHeight: root.vertical ? root.verticalLines.length * Style.bar.iconSlot : -1
horizontalMargin: 8.75
verticalPadding: 8.75
onPressed: function(button) {
if (!root.bar) return
if (button === Qt.RightButton) root.bar.run("omarchy-menu-timezone")
else root.alt = !root.alt
}
Column {
visible: root.vertical
anchors.fill: parent
Repeater {
model: root.verticalLines
OpticalGlyph {
required property string modelData
width: button.width
height: Style.bar.iconSlot
text: modelData
fontFamily: button.fontFamily
fontSize: modelData.length > 3
? button.fontSize * 0.9
: button.fontSize
color: button.foreground
}
}
}
}
}