Build the Prism calendar Daybook

This commit is contained in:
Gabriel Brown
2026-08-17 11:38:24 -04:00
parent 6a1bec849d
commit 03914e23af
9 changed files with 724 additions and 165 deletions
@@ -0,0 +1,128 @@
import QtQuick
import qs.config
import qs.services
Item {
id: root
required property var eventData
property bool past: false
signal activated
signal joinRequested
readonly property var sourceData: CalendarAgenda.sourceForId(eventData.sourceId)
readonly property color eventColor: sourceData?.color ?? Theme.accent
readonly property string timeText: eventData.allDay
? "All day"
: Qt.formatTime(new Date(Number(eventData.start) * 1000), Settings.use24Hour ? "HH:mm" : "h:mm AP")
readonly property string detailText: {
const source = root.sourceData?.name ?? "Calendar";
const location = String(root.eventData.location ?? "").trim();
return location === "" ? source : source + " · " + location;
}
implicitHeight: 58
opacity: past ? 0.52 : 1
Rectangle {
anchors.fill: parent
radius: 9
border.width: 0
color: rowMouse.containsMouse ? Theme.alpha(Theme.fg, 0.07) : "transparent"
Behavior on color { ColorAnimation { duration: Theme.durFast } }
}
MouseArea {
id: rowMouse
anchors.fill: parent
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
onClicked: root.activated()
}
Text {
id: timeLabel
anchors.left: parent.left
anchors.verticalCenter: parent.verticalCenter
width: 56
text: root.timeText
color: Theme.fgDim
horizontalAlignment: Text.AlignRight
font.family: Theme.fontFamily
font.features: Theme.tabularFigures
font.pixelSize: Theme.fontSizeSmall
}
Rectangle {
id: sourceRail
anchors.left: timeLabel.right
anchors.leftMargin: 10
anchors.verticalCenter: parent.verticalCenter
width: 3
height: 34
radius: 2
border.width: 0
color: root.eventColor
}
Column {
anchors.left: sourceRail.right
anchors.leftMargin: 10
anchors.right: joinPill.visible ? joinPill.left : parent.right
anchors.rightMargin: joinPill.visible ? 10 : 4
anchors.verticalCenter: parent.verticalCenter
spacing: 3
Text {
width: parent.width
text: root.eventData.summary || "Untitled event"
color: Theme.fg
elide: Text.ElideRight
font.family: Theme.fontFamily
font.pixelSize: Theme.fontSize
font.weight: Font.DemiBold
}
Text {
width: parent.width
text: root.detailText
color: Theme.fgDim
elide: Text.ElideRight
font.family: Theme.fontFamily
font.pixelSize: Theme.fontSizeSmall
}
}
Rectangle {
id: joinPill
anchors.right: parent.right
anchors.rightMargin: 4
anchors.verticalCenter: parent.verticalCenter
visible: String(root.eventData.joinUrl ?? "").startsWith("https://")
width: joinLabel.implicitWidth + 18
height: 26
radius: Theme.pillRadius
border.width: 0
color: joinMouse.containsMouse ? Theme.alpha(Theme.accent, 0.28) : Theme.alpha(Theme.accent, 0.14)
Text {
id: joinLabel
anchors.centerIn: parent
text: "Join"
color: Theme.accent
font.family: Theme.fontFamily
font.pixelSize: Theme.fontSizeSmall
font.weight: Font.DemiBold
}
MouseArea {
id: joinMouse
anchors.fill: parent
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
onClicked: root.joinRequested()
}
}
}
@@ -0,0 +1,298 @@
import QtQuick
import Quickshell
import qs.config
import qs.services
import qs.modules.quicksettings
Item {
id: root
signal requestNotifications
readonly property bool isToday: CalendarAgenda.selectedDateKey === CalendarAgenda.dateKey(clock.date)
readonly property var upNext: CalendarAgenda.nextEventForSelectedDate
readonly property var listedEvents: CalendarAgenda.selectedEvents.filter(event => !root.upNext || event.id !== root.upNext.id)
readonly property string selectedLabel: root.isToday
? "Today"
: Qt.formatDate(CalendarAgenda.selectedDate, "dddd, MMMM d")
implicitHeight: content.implicitHeight
SystemClock {
id: clock
precision: SystemClock.Minutes
}
Column {
id: content
width: parent.width
spacing: 12
Column {
width: parent.width
spacing: 3
visible: CalendarAgenda.phase === "loading"
Text {
text: "CALENDAR"
color: Theme.fgMuted
font.family: Theme.fontFamily
font.pixelSize: Theme.fontSizeSmall
font.weight: Font.DemiBold
font.letterSpacing: 1.1
}
Text {
text: "Loading calendars…"
color: Theme.fgDim
font.family: Theme.fontFamily
font.pixelSize: Theme.fontSizeLarge
font.weight: Font.DemiBold
}
}
Column {
width: parent.width
spacing: 10
visible: CalendarAgenda.phase === "unavailable"
Text {
text: "Calendar data is unavailable"
color: Theme.fg
font.family: Theme.fontFamily
font.pixelSize: Theme.fontSizeLarge
font.weight: Font.DemiBold
}
Text {
width: parent.width
wrapMode: Text.WordWrap
text: "Notifications, weather, and the month grid are still available. GNOME Calendar may have more detail."
color: Theme.fgDim
font.family: Theme.fontFamily
font.pixelSize: Theme.fontSize
}
ActionPill {
text: "Open Calendar"
onClicked: CalendarAgenda.openCalendar(CalendarAgenda.selectedDate)
}
}
Rectangle {
id: nextCard
width: parent.width
height: visible ? 88 : 0
visible: CalendarAgenda.available && root.isToday && root.upNext !== null
radius: Theme.cardRadius
border.width: 1
border.color: Theme.alpha(Theme.accent, 0.18)
color: Theme.alpha(Theme.accent, 0.105)
clip: true
Rectangle {
anchors.right: parent.right
anchors.rightMargin: -24
anchors.bottom: parent.bottom
anchors.bottomMargin: -34
width: 110
height: 110
radius: 55
border.width: 0
color: Theme.alpha(Theme.accentSecondary, 0.08)
}
Column {
anchors.left: parent.left
anchors.leftMargin: 14
anchors.right: nextJoin.visible ? nextJoin.left : parent.right
anchors.rightMargin: nextJoin.visible ? 10 : 14
anchors.verticalCenter: parent.verticalCenter
spacing: 5
Text {
text: "UP NEXT · " + root.relativeStart(root.upNext)
color: Theme.accent
font.family: Theme.fontFamily
font.features: Theme.tabularFigures
font.pixelSize: Theme.fontSizeSmall
font.weight: Font.Bold
font.letterSpacing: 0.8
}
Text {
width: parent.width
text: root.upNext?.summary ?? ""
color: Theme.fg
elide: Text.ElideRight
font.family: Theme.fontFamily
font.pixelSize: Theme.fontSizeLarge
font.weight: Font.DemiBold
}
Text {
width: parent.width
text: root.eventDetail(root.upNext)
color: Theme.fgDim
elide: Text.ElideRight
font.family: Theme.fontFamily
font.pixelSize: Theme.fontSizeSmall
}
}
ActionPill {
id: nextJoin
anchors.right: parent.right
anchors.rightMargin: 12
anchors.top: parent.top
anchors.topMargin: 12
visible: String(root.upNext?.joinUrl ?? "").startsWith("https://")
text: "Join"
accent: true
onClicked: CalendarAgenda.join(root.upNext)
}
MouseArea {
anchors.fill: parent
z: -1
cursorShape: Qt.PointingHandCursor
onClicked: CalendarAgenda.openEvent(root.upNext)
}
}
Item {
width: parent.width
height: 34
visible: CalendarAgenda.available
Column {
anchors.left: parent.left
anchors.verticalCenter: parent.verticalCenter
spacing: 2
Text {
text: root.selectedLabel.toUpperCase()
color: Theme.fgMuted
font.family: Theme.fontFamily
font.pixelSize: Theme.fontSizeSmall
font.weight: Font.DemiBold
font.letterSpacing: 0.9
}
Text {
text: "Your schedule"
color: Theme.fg
font.family: Theme.fontFamily
font.pixelSize: Theme.fontSizeLarge
font.weight: Font.DemiBold
}
}
Text {
anchors.right: parent.right
anchors.bottom: parent.bottom
text: CalendarAgenda.selectedEvents.length + (CalendarAgenda.selectedEvents.length === 1 ? " event" : " events")
color: Theme.fgDim
font.family: Theme.fontFamily
font.features: Theme.tabularFigures
font.pixelSize: Theme.fontSizeSmall
}
}
Item {
width: parent.width
height: visible ? 92 : 0
visible: CalendarAgenda.available && CalendarAgenda.selectedEvents.length === 0
Column {
anchors.centerIn: parent
spacing: 8
Text {
anchors.horizontalCenter: parent.horizontalCenter
text: "Nothing scheduled"
color: Theme.fgDim
font.family: Theme.fontFamily
font.pixelSize: Theme.fontSize
}
ActionPill {
anchors.horizontalCenter: parent.horizontalCenter
text: "Open Calendar"
onClicked: CalendarAgenda.openCalendar(CalendarAgenda.selectedDate)
}
}
}
ScrollColumn {
width: parent.width
maxHeight: 286
spacing: 0
visible: CalendarAgenda.available && root.listedEvents.length > 0
Repeater {
model: root.listedEvents
AgendaEvent {
required property var modelData
width: parent.width
eventData: modelData
past: Number(modelData.end) <= CalendarAgenda.nowEpoch
onActivated: CalendarAgenda.openEvent(modelData)
onJoinRequested: CalendarAgenda.join(modelData)
}
}
}
NotificationSummary {
width: parent.width
onActivated: root.requestNotifications()
}
}
function relativeStart(event: var): string {
if (!event)
return "";
const seconds = Number(event.start) - CalendarAgenda.nowEpoch;
if (seconds <= 0)
return "NOW";
if (seconds < 3600)
return "IN " + Math.ceil(seconds / 60) + " MINUTES";
return Qt.formatTime(new Date(Number(event.start) * 1000), Settings.use24Hour ? "HH:mm" : "h:mm AP");
}
function eventDetail(event: var): string {
if (!event)
return "";
const source = CalendarAgenda.sourceForId(event.sourceId)?.name ?? "Calendar";
const location = String(event.location ?? "").trim();
return location === "" ? source : source + " · " + location;
}
component ActionPill: Rectangle {
id: action
required property string text
property bool accent: false
signal clicked
width: actionLabel.implicitWidth + 20
height: 28
radius: Theme.pillRadius
border.width: 0
color: actionMouse.containsMouse
? Theme.alpha(action.accent ? Theme.accent : Theme.fg, 0.24)
: Theme.alpha(action.accent ? Theme.accent : Theme.fg, action.accent ? 0.14 : 0.07)
Text {
id: actionLabel
anchors.centerIn: parent
text: action.text
color: action.accent ? Theme.accent : Theme.fg
font.family: Theme.fontFamily
font.pixelSize: Theme.fontSizeSmall
font.weight: Font.DemiBold
}
MouseArea {
id: actionMouse
anchors.fill: parent
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
onClicked: action.clicked()
}
}
}
@@ -29,7 +29,7 @@ PanelWindow {
margins.top: Theme.barHeight + Theme.barGap * 2
exclusiveZone: 0
implicitWidth: panel.implicitWidth
implicitWidth: 760
implicitHeight: panel.implicitHeight
// The `qs-popover` prefix is matched by a layerrule in hypr/rules.lua.
@@ -41,15 +41,24 @@ PanelWindow {
onVisibleChanged: {
if (root.visible) {
// Opening the tray is what marks everything read, same as GNOME.
Notifs.markAllRead();
panel.prepare();
CalendarAgenda.refresh();
if (ShellState.dateMenuPage === "notifications")
Notifs.markAllRead();
panel.prepare(ShellState.dateMenuPage);
openAnim.restart();
} else {
panel.reset();
}
}
Connections {
target: ShellState
function onDateMenuPageChanged(): void {
if (root.visible && ShellState.dateMenuPage === "notifications")
Notifs.markAllRead();
}
}
// Closes the panel when a click lands anywhere else on the desktop.
HyprlandFocusGrab {
windows: [root]
@@ -1,9 +1,5 @@
// The contents of the date menu, in GNOME's order: date header, notifications,
// calendar, weather.
//
// Kept separate from DateMenu.qml (the PanelWindow) so it can be dropped into a
// FloatingWindow for testing — layer-shell surfaces cannot map outside a
// wlroots compositor.
// The approved A · Daybook: month context on the left, the selected day's
// schedule or grouped notification history on the right.
import QtQuick
import Quickshell
@@ -14,38 +10,38 @@ import qs.widgets
Item {
id: root
implicitWidth: 480
implicitHeight: content.implicitHeight + Theme.popoverPadding * 2
implicitWidth: 760
implicitHeight: frame.implicitHeight + Theme.popoverPadding * 2
// Called by the window when it opens and closes, so the panel is always in
// a known state rather than wherever the last visit left it.
function prepare(): void {
function prepare(page: string): void {
calendar.showToday();
CalendarAgenda.selectDate(clock.date);
CalendarAgenda.setVisibleMonth(clock.date.getFullYear(), clock.date.getMonth());
if (page === "notifications")
Notifs.markAllRead();
}
function reset(): void {
notifications.reset();
}
// Minutes precision: the header only shows a date, so this exists purely to
// roll it over at midnight without a per-second wake.
SystemClock {
id: clock
precision: SystemClock.Minutes
}
Column {
id: content
id: frame
anchors.left: parent.left
anchors.right: parent.right
anchors.top: parent.top
anchors.margins: Theme.popoverPadding
spacing: Theme.sectionSpacing
spacing: 0
// ── Header ──────────────────────────────────────────────────────────
Item {
id: header
width: parent.width
height: 34
height: 42
Text {
anchors.left: parent.left
@@ -57,7 +53,6 @@ Item {
color: Theme.fg
elide: Text.ElideRight
font.family: Theme.fontFamily
// The day number changes in place at midnight.
font.features: Theme.tabularFigures
font.pixelSize: Theme.fontSizeTitle
font.weight: Font.DemiBold
@@ -69,153 +64,210 @@ Item {
anchors.verticalCenter: parent.verticalCenter
spacing: 6
// Labelled rather than icon-only: an unexplained crossed-out
// bell is exactly the kind of thing a normal person has to
// click to find out about.
Rectangle {
id: dndPill
anchors.verticalCenter: parent.verticalCenter
width: dndRow.implicitWidth + 20
height: 28
radius: Theme.pillRadius
border.width: 0
color: {
if (Notifs.doNotDisturb)
return dndMouse.containsMouse ? Theme.alpha(Theme.accent, 0.42) : Theme.alpha(Theme.accent, 0.28);
return dndMouse.containsMouse ? Theme.alpha(Theme.fg, 0.16) : Theme.alpha(Theme.fg, 0.08);
}
Behavior on color {
ColorAnimation {
duration: dndMouse.containsMouse ? Theme.durFast : Theme.durNormal
}
}
Row {
id: dndRow
anchors.centerIn: parent
spacing: 6
ThemedIcon {
anchors.verticalCenter: parent.verticalCenter
size: 14
icon: "notifications-disabled-symbolic"
iconFallback: "user-invisible-symbolic"
tint: Notifs.doNotDisturb ? Theme.accent : Theme.fgDim
}
Text {
anchors.verticalCenter: parent.verticalCenter
text: "Do Not Disturb"
color: Notifs.doNotDisturb ? Theme.accent : Theme.fg
font.family: Theme.fontFamily
font.pixelSize: Theme.fontSizeSmall
font.weight: Font.Medium
}
}
MouseArea {
id: dndMouse
anchors.fill: parent
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
onClicked: Notifs.doNotDisturb = !Notifs.doNotDisturb
}
HeaderPill {
visible: ShellState.dateMenuPage === "notifications"
text: "← Back to agenda"
onClicked: ShellState.dateMenuPage = "agenda"
}
Rectangle {
id: clearPill
anchors.verticalCenter: parent.verticalCenter
width: clearLabel.implicitWidth + 20
height: 28
radius: Theme.pillRadius
border.width: 0
// Hidden rather than disabled: there is nothing ambiguous
// about an empty tray, so the control has no job.
visible: Notifs.hasNotifications
color: clearMouse.containsMouse ? Theme.alpha(Theme.fg, 0.16) : Theme.alpha(Theme.fg, 0.08)
HeaderPill {
text: "Do Not Disturb"
active: Notifs.doNotDisturb
icon: "notifications-disabled-symbolic"
onClicked: Notifs.doNotDisturb = !Notifs.doNotDisturb
}
Behavior on color {
ColorAnimation {
duration: clearMouse.containsMouse ? Theme.durFast : Theme.durNormal
}
}
HeaderPill {
visible: ShellState.dateMenuPage === "agenda"
text: "Open Calendar ↗"
onClicked: CalendarAgenda.openCalendar(CalendarAgenda.selectedDate)
}
Text {
id: clearLabel
anchors.centerIn: parent
text: "Clear all"
color: Theme.fg
font.family: Theme.fontFamily
font.pixelSize: Theme.fontSizeSmall
font.weight: Font.Medium
}
MouseArea {
id: clearMouse
anchors.fill: parent
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
onClicked: Notifs.dismissAll()
}
HeaderPill {
visible: ShellState.dateMenuPage === "notifications" && Notifs.hasNotifications
text: "Clear all"
onClicked: Notifs.dismissAll()
}
}
}
// ── Notifications ───────────────────────────────────────────────────
Rectangle {
width: parent.width
height: 1
border.width: 0
color: Theme.alpha(Theme.fg, 0.1)
color: Theme.alpha(Theme.fg, 0.10)
}
MediaCard {
id: media
Row {
id: body
width: parent.width
height: Math.min(620, Math.max(438, leftContent.implicitHeight + 28, rightContentHeight + 28))
Item {
id: leftColumn
width: 310
height: body.height
Column {
id: leftContent
anchors.left: parent.left
anchors.right: parent.right
anchors.top: parent.top
anchors.margins: 14
spacing: 12
CalendarGrid {
id: calendar
width: parent.width
selectedDate: CalendarAgenda.selectedDate
onDateActivated: date => CalendarAgenda.selectDate(date)
onVisibleMonthChanged: (year, month) => CalendarAgenda.setVisibleMonth(year, month)
}
Rectangle {
width: parent.width
height: 1
border.width: 0
visible: media.visible || Weather.available
color: Theme.alpha(Theme.fg, 0.08)
}
MediaCard {
id: media
width: parent.width
}
WeatherCard {
width: parent.width
visible: Weather.available
}
}
}
Rectangle {
width: 1
height: body.height
border.width: 0
color: Theme.alpha(Theme.fg, 0.10)
}
Item {
id: rightColumn
width: body.width - leftColumn.width - 1
height: body.height
readonly property real availableWidth: width - 28
AgendaPane {
id: agenda
anchors.left: parent.left
anchors.right: parent.right
anchors.top: parent.top
anchors.margins: 14
visible: ShellState.dateMenuPage === "agenda"
onRequestNotifications: {
ShellState.dateMenuPage = "notifications";
Notifs.markAllRead();
}
}
Column {
id: notificationPane
anchors.left: parent.left
anchors.right: parent.right
anchors.top: parent.top
anchors.margins: 14
spacing: 10
visible: ShellState.dateMenuPage === "notifications"
Item {
width: parent.width
height: 28
Text {
anchors.left: parent.left
anchors.verticalCenter: parent.verticalCenter
text: "Notifications"
color: Theme.fg
font.family: Theme.fontFamily
font.pixelSize: Theme.fontSizeLarge
font.weight: Font.DemiBold
}
Text {
anchors.right: parent.right
anchors.verticalCenter: parent.verticalCenter
text: Notifs.history.length + (Notifs.history.length === 1 ? " item" : " items")
color: Theme.fgDim
font.family: Theme.fontFamily
font.features: Theme.tabularFigures
font.pixelSize: Theme.fontSizeSmall
}
}
NotificationList {
id: notifications
width: parent.width
maxHeight: body.height - 76
}
}
}
}
}
readonly property real rightContentHeight: ShellState.dateMenuPage === "notifications"
? notificationPane.implicitHeight
: agenda.implicitHeight
component HeaderPill: Rectangle {
id: pill
required property string text
property string icon: ""
property bool active: false
signal clicked
width: pillRow.implicitWidth + 20
height: 28
radius: Theme.pillRadius
border.width: 0
color: {
if (pill.active)
return pillMouse.containsMouse ? Theme.alpha(Theme.accent, 0.38) : Theme.alpha(Theme.accent, 0.24);
return pillMouse.containsMouse ? Theme.alpha(Theme.fg, 0.15) : Theme.alpha(Theme.fg, 0.07);
}
Rectangle {
width: parent.width
height: 1
border.width: 0
visible: media.visible
color: Theme.alpha(Theme.fg, 0.1)
Behavior on color { ColorAnimation { duration: Theme.durFast } }
Row {
id: pillRow
anchors.centerIn: parent
spacing: 6
ThemedIcon {
anchors.verticalCenter: parent.verticalCenter
visible: pill.icon !== ""
size: visible ? 14 : 0
icon: pill.icon
tint: pill.active ? Theme.accent : Theme.fgDim
}
Text {
anchors.verticalCenter: parent.verticalCenter
text: pill.text
color: pill.active ? Theme.accent : Theme.fg
font.family: Theme.fontFamily
font.pixelSize: Theme.fontSizeSmall
font.weight: Font.Medium
}
}
NotificationList {
id: notifications
width: parent.width
}
// ── Calendar ────────────────────────────────────────────────────────
Rectangle {
width: parent.width
height: 1
border.width: 0
color: Theme.alpha(Theme.fg, 0.1)
}
CalendarGrid {
id: calendar
width: parent.width
}
// ── Weather ─────────────────────────────────────────────────────────
// Separator and card share one condition so the panel does not end on a
// rule with nothing under it.
Rectangle {
width: parent.width
height: 1
border.width: 0
visible: Weather.available
color: Theme.alpha(Theme.fg, 0.1)
}
WeatherCard {
width: parent.width
visible: Weather.available
MouseArea {
id: pillMouse
anchors.fill: parent
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
onClicked: pill.clicked()
}
}
}
@@ -9,13 +9,15 @@ import qs.widgets
Rectangle {
id: root
readonly property bool compact: width < 360
readonly property MprisPlayer player: {
const players = Mpris.players ? Mpris.players.values : [];
return players.find(p => p.isPlaying) ?? players.find(p => p.trackTitle) ?? null;
}
visible: root.player !== null
implicitHeight: visible ? 76 : 0
implicitHeight: visible ? (compact ? 64 : 76) : 0
radius: Theme.cardRadius
border.width: 0
color: Theme.alpha(Theme.fg, 0.06)
@@ -24,11 +26,11 @@ Rectangle {
Rectangle {
id: artwork
anchors.left: parent.left
anchors.leftMargin: 10
anchors.leftMargin: root.compact ? 8 : 10
anchors.verticalCenter: parent.verticalCenter
width: 56
height: 56
radius: 10
width: root.compact ? 46 : 56
height: width
radius: root.compact ? 9 : 10
border.width: 0
color: Theme.alpha(Theme.accentAlt, 0.16)
clip: true
@@ -54,9 +56,9 @@ Rectangle {
Column {
anchors.left: artwork.right
anchors.leftMargin: 12
anchors.leftMargin: root.compact ? 9 : 12
anchors.right: controls.left
anchors.rightMargin: 10
anchors.rightMargin: root.compact ? 6 : 10
anchors.verticalCenter: parent.verticalCenter
spacing: 3
@@ -83,7 +85,7 @@ Rectangle {
Row {
id: controls
anchors.right: parent.right
anchors.rightMargin: 10
anchors.rightMargin: root.compact ? 7 : 10
anchors.verticalCenter: parent.verticalCenter
spacing: 2
@@ -114,7 +116,7 @@ Rectangle {
property bool emphasized: false
signal clicked
width: emphasized ? 34 : 30
width: root.compact ? (emphasized ? 30 : 27) : (emphasized ? 34 : 30)
height: width
radius: width / 2
border.width: 0
@@ -0,0 +1,58 @@
import QtQuick
import qs.config
import qs.services
Rectangle {
id: root
signal activated
visible: Notifs.hasNotifications
implicitHeight: visible ? 62 : 0
radius: Theme.cardRadius
border.width: 0
color: summaryMouse.containsMouse ? Theme.alpha(Theme.fg, 0.10) : Theme.alpha(Theme.fg, 0.055)
Behavior on color { ColorAnimation { duration: Theme.durFast } }
Column {
anchors.left: parent.left
anchors.leftMargin: 14
anchors.verticalCenter: parent.verticalCenter
spacing: 3
Text {
text: Notifs.history.length + (Notifs.history.length === 1 ? " notification" : " notifications")
color: Theme.fg
font.family: Theme.fontFamily
font.pixelSize: Theme.fontSize
font.weight: Font.DemiBold
}
Text {
text: "Grouped quietly until you open them"
color: Theme.fgDim
font.family: Theme.fontFamily
font.pixelSize: Theme.fontSizeSmall
}
}
Text {
anchors.right: parent.right
anchors.rightMargin: 14
anchors.verticalCenter: parent.verticalCenter
text: "View →"
color: Theme.fgDim
font.family: Theme.fontFamily
font.pixelSize: Theme.fontSizeSmall
font.weight: Font.Medium
}
MouseArea {
id: summaryMouse
anchors.fill: parent
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
onClicked: root.activated()
}
}
@@ -1,4 +1,6 @@
module qs.modules.datemenu
AgendaEvent 1.0 AgendaEvent.qml
AgendaPane 1.0 AgendaPane.qml
CalendarGrid 1.0 CalendarGrid.qml
DateMenu 1.0 DateMenu.qml
DateMenuPanel 1.0 DateMenuPanel.qml
@@ -6,4 +8,5 @@ MediaCard 1.0 MediaCard.qml
MonthArrow 1.0 MonthArrow.qml
NotificationGroup 1.0 NotificationGroup.qml
NotificationList 1.0 NotificationList.qml
NotificationSummary 1.0 NotificationSummary.qml
WeatherCard 1.0 WeatherCard.qml