diff options
Diffstat (limited to 'desktop/modules/island')
| -rw-r--r-- | desktop/modules/island/IslandClockModule.qml | 247 |
1 files changed, 247 insertions, 0 deletions
diff --git a/desktop/modules/island/IslandClockModule.qml b/desktop/modules/island/IslandClockModule.qml new file mode 100644 index 0000000..ef8c204 --- /dev/null +++ b/desktop/modules/island/IslandClockModule.qml @@ -0,0 +1,247 @@ +// Copyright (C) 2026 Danilo M. <danix@danix.xyz> +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +import Quickshell +import QtQuick +import "../.." +import "../appearance" +import "../../island/calendar/Cal.js" as Cal + +// How the island shows time and dates: the clock pill, the calendar's day +// headings, agenda times and hour picker. +Module { + id: mod + name: "island-clock" + label: "Date and time" + // nf-md-clock_outline, present in Inconsolata Nerd Font. + icon: "\u{f0150}" + settings: true + group: "Island bar" + keywords: ["island", "clock", "time", "date", "format", "12-hour", "24-hour", "am", "pm", "day", "month"] + searchItems: [{ text: "Clock", key: "h12" }, { text: "Date format", key: "dateFormat" }] + + property bool h12: Prefs.island.h12 + property string dateFormat: Prefs.island.dateFormat + dirty: h12 !== Prefs.island.h12 || dateFormat !== Prefs.island.dateFormat + function refresh() { if (!mod.dirty) mod.discard(); } + function discard() { mod.h12 = Prefs.island.h12; mod.dateFormat = Prefs.island.dateFormat; } + + page: Component { + Page { + title: "Date and time" + actions: Component { + SaveBar { + dirty: mod.dirty + onSave: Prefs.setIsland({ h12: mod.h12, dateFormat: mod.dateFormat }) + onDiscard: mod.discard() + } + } + Flow { + id: body + width: parent.width + spacing: 32 + SystemClock { id: now; precision: SystemClock.Minutes } + readonly property string today: Cal.today(now.date) + // Two made-up events today, one each side of noon. + readonly property var events: [ + { title: "Standup", allDay: false, start: today + "T09:30", end: today + "T10:00", color: "blue" }, + { title: "Dinner", allDay: false, start: today + "T20:30", end: today + "T22:00", color: "green" }] + + Column { + id: controls + width: 3 * 120 + 2 * 12 + spacing: 6 + + Heading { text: "Clock" } + Hint { text: "The clock pill, the agenda and the hour picker. Event times can also be typed with am and pm (9.30pm)." } + Row { + objectName: "h12" + spacing: 6 + Tab { text: "24-hour"; selected: !mod.h12; onClicked: mod.h12 = false } + Tab { text: "12-hour"; selected: mod.h12; onClicked: mod.h12 = true } + } + + Item { width: 1; height: 14 } + Heading { text: "Date" } + Hint { text: "The clock pill. The calendar spells the month out, in the same order." } + Row { + objectName: "dateFormat" + spacing: 12 + Repeater { + model: Cal.DATE_GROUPS + delegate: Column { + required property var modelData + width: 120 + spacing: 2 + Text { + text: modelData.title + color: Theme.subtext + bottomPadding: 4 + font { family: Theme.fontFamily; pixelSize: Theme.fontSize - 4 } + } + Repeater { + model: modelData.formats + delegate: Rectangle { + required property string modelData + readonly property bool on: mod.dateFormat === modelData + width: 120 + height: 26 + radius: 6 + color: on ? Qt.alpha(Theme.accent, 0.25) + : pick.containsMouse ? Qt.alpha(Theme.surface, 0.8) : "transparent" + border.width: on ? 1 : 0 + border.color: Qt.alpha(Theme.accent, 0.5) + Text { + anchors { left: parent.left; leftMargin: 8; verticalCenter: parent.verticalCenter } + text: Qt.formatDate(now.date, parent.modelData) + color: parent.on ? Theme.text : Theme.subtext + font { family: Theme.fontFamily; pixelSize: Theme.fontSize - 3 } + } + MouseArea { + id: pick + anchors.fill: parent + hoverEnabled: true + cursorShape: Qt.PointingHandCursor + onClicked: mod.dateFormat = parent.modelData + } + } + } + } + } + } + } + + // Beside the controls when there is room, below them when not. + Column { + width: Math.max(220, Math.min(400, body.width - controls.width - body.spacing)) + spacing: 6 + Heading { text: "Preview" } + Hint { text: "With the unsaved choice." } + // A mock of the island: the clock pill at rest, and the + // calendar panel's heading, agenda and hour picker below it. + Rectangle { + width: parent.width + height: mock.implicitHeight + 32 + radius: 12 + color: Qt.alpha(Theme.surface, 0.35) + + Column { + id: mock + anchors { fill: parent; margins: 16 } + spacing: 14 + + Rectangle { + anchors.horizontalCenter: parent.horizontalCenter + width: pillRow.implicitWidth + 28 + height: 34 + radius: 17 + color: Qt.alpha(Theme.base, 0.92) + border.width: 1 + border.color: Qt.alpha(Theme.text, 0.12) + Row { + id: pillRow + anchors.centerIn: parent + spacing: 10 + Text { + anchors.verticalCenter: parent.verticalCenter + text: Qt.formatDateTime(now.date, Cal.shortDateFmt(mod.dateFormat)) + color: Theme.subtext + font { family: Theme.fontFamily; pixelSize: Theme.fontSize - 2 } + } + Text { + anchors.verticalCenter: parent.verticalCenter + text: Qt.formatDateTime(now.date, Cal.timeFmt(mod.h12)) + color: Theme.text + font { family: Theme.fontFamily; pixelSize: Theme.fontSize; weight: Font.DemiBold } + } + } + } + + Rectangle { + width: parent.width + height: panelCol.implicitHeight + 24 + radius: 17 + color: Qt.alpha(Theme.base, 0.92) + border.width: 1 + border.color: Qt.alpha(Theme.text, 0.12) + Column { + id: panelCol + anchors { fill: parent; margins: 12 } + spacing: 6 + Text { + text: Qt.formatDate(now.date, Cal.dayFmt(mod.dateFormat, true)) + color: Theme.text + font { family: Theme.fontFamily; pixelSize: Theme.fontSize - 2; bold: true } + } + Repeater { + model: body.events + delegate: Row { + required property var modelData + spacing: 8 + Rectangle { width: 3; height: 16; radius: 1; color: Theme[modelData.color] } + Text { + width: mod.h12 ? 92 : 82 + text: Cal.timeLabel(modelData, body.today, mod.h12) + color: Theme.subtext + font { family: Theme.fontFamily; pixelSize: Theme.fontSize - 5 } + } + Text { + text: modelData.title + color: Theme.text + font { family: Theme.fontFamily; pixelSize: Theme.fontSize - 4 } + } + } + } + Text { + text: "When " + Qt.formatDate(now.date, Cal.dayFmt(mod.dateFormat, false)) + color: Theme.subtext + font { family: Theme.fontFamily; pixelSize: Theme.fontSize - 4 } + } + Row { + spacing: 2 + Repeater { + model: [8, 9, 10, 11, 12] + delegate: Rectangle { + required property int modelData + width: 34 + height: 26 + radius: 6 + color: modelData === 9 ? Qt.alpha(Theme.accent, 0.35) : "transparent" + Text { + anchors.centerIn: parent + text: Cal.hourLabel(parent.modelData, mod.h12) + color: Theme.text + font { family: Theme.fontFamily; pixelSize: Theme.fontSize - 4 } + } + } + } + } + } + } + } + } + } + } + } + } + + component Heading: Text { + font { family: Theme.fontFamily; pixelSize: Theme.fontSize - 3; bold: true } + color: Theme.text + } + + component Hint: Text { + width: parent ? parent.width : 0 + wrapMode: Text.WordWrap + color: Theme.overlay + font { family: Theme.fontFamily; pixelSize: Theme.fontSize - 4 } + } +} |
