summaryrefslogtreecommitdiff
path: root/raveos-hyprland-theme/theme-data/dms/Modules/DankDash/Overview
diff options
context:
space:
mode:
Diffstat (limited to 'raveos-hyprland-theme/theme-data/dms/Modules/DankDash/Overview')
-rw-r--r--raveos-hyprland-theme/theme-data/dms/Modules/DankDash/Overview/CalendarOverviewCard.qml539
-rw-r--r--raveos-hyprland-theme/theme-data/dms/Modules/DankDash/Overview/Card.qml24
-rw-r--r--raveos-hyprland-theme/theme-data/dms/Modules/DankDash/Overview/ClockCard.qml113
-rw-r--r--raveos-hyprland-theme/theme-data/dms/Modules/DankDash/Overview/MediaOverviewCard.qml211
-rw-r--r--raveos-hyprland-theme/theme-data/dms/Modules/DankDash/Overview/SystemMonitorCard.qml178
-rw-r--r--raveos-hyprland-theme/theme-data/dms/Modules/DankDash/Overview/UserInfoCard.qml110
-rw-r--r--raveos-hyprland-theme/theme-data/dms/Modules/DankDash/Overview/WeatherOverviewCard.qml94
7 files changed, 1269 insertions, 0 deletions
diff --git a/raveos-hyprland-theme/theme-data/dms/Modules/DankDash/Overview/CalendarOverviewCard.qml b/raveos-hyprland-theme/theme-data/dms/Modules/DankDash/Overview/CalendarOverviewCard.qml
new file mode 100644
index 0000000..1972f06
--- /dev/null
+++ b/raveos-hyprland-theme/theme-data/dms/Modules/DankDash/Overview/CalendarOverviewCard.qml
@@ -0,0 +1,539 @@
+import QtQuick
+import Quickshell
+import qs.Common
+import qs.Services
+import qs.Widgets
+
+Rectangle {
+ id: root
+
+ implicitWidth: SettingsData.showWeekNumber ? 736 : 700
+
+ property bool showEventDetails: false
+ property date selectedDate: systemClock.date
+ property var selectedDateEvents: []
+ property bool hasEvents: selectedDateEvents && selectedDateEvents.length > 0
+
+ signal closeDash
+
+ function weekStartQt() {
+ if (SettingsData.firstDayOfWeek >= 7 || SettingsData.firstDayOfWeek < 0) {
+ return Qt.locale().firstDayOfWeek;
+ }
+ return SettingsData.firstDayOfWeek;
+ }
+
+ function weekStartJs() {
+ return weekStartQt() % 7;
+ }
+
+ function startOfWeek(dateObj) {
+ const d = new Date(dateObj);
+ const jsDow = d.getDay();
+ const diff = (jsDow - weekStartJs() + 7) % 7;
+ d.setDate(d.getDate() - diff);
+ return d;
+ }
+
+ function endOfWeek(dateObj) {
+ const d = new Date(dateObj);
+ const jsDow = d.getDay();
+ const add = (weekStartJs() + 6 - jsDow + 7) % 7;
+ d.setDate(d.getDate() + add);
+ return d;
+ }
+
+ function getWeekNumber(dateObj) {
+ // Set time to noon to avoid potential Daylight Saving Time related bugs
+ const weekStartDay = startOfWeek(dateObj);
+ weekStartDay.setHours(12, 0, 0, 0);
+
+ let week1Start;
+
+ if (weekStartJs() === 1) {
+ // ISO 8601 Standard, week start on Monday
+ // A week belongs to the year its Thursday falls in
+ // So we have to get the yearTarget from weekStartDay instead of dateObj
+ let yearTarget = weekStartDay;
+ yearTarget.setDate(yearTarget.getDate() + 3); // Monday + 3 = Thursday
+
+ // Week 1 is the week containing Jan 4th
+ const jan4 = new Date(yearTarget.getFullYear(), 0, 4);
+ week1Start = startOfWeek(jan4);
+ } else {
+ // Traditional / US Standard, week start on Sunday
+ // A week belongs to the year its Sunday falls in
+ let yearTarget = weekStartDay;
+ yearTarget.setDate(yearTarget.getDate() + 6); // Monday + 6 = Sunday
+
+ // Week 1 is the week containing Jan 1st
+ const jan1 = new Date(yearTarget.getFullYear(), 0, 1);
+ week1Start = startOfWeek(jan1);
+ }
+
+ week1Start.setHours(12, 0, 0, 0);
+
+ const diffDays = Math.round((weekStartDay.getTime() - week1Start.getTime()) / 86400000); // Number of miliseconds in a day
+ return Math.floor(diffDays / 7) + 1;
+ }
+
+ function updateSelectedDateEvents() {
+ if (CalendarService && CalendarService.khalAvailable) {
+ const events = CalendarService.getEventsForDate(selectedDate);
+ selectedDateEvents = events;
+ } else {
+ selectedDateEvents = [];
+ }
+ }
+
+ function loadEventsForMonth() {
+ if (!CalendarService || !CalendarService.khalAvailable) {
+ return;
+ }
+
+ const firstOfMonth = new Date(calendarGrid.displayDate.getFullYear(), calendarGrid.displayDate.getMonth(), 1);
+ const lastOfMonth = new Date(calendarGrid.displayDate.getFullYear(), calendarGrid.displayDate.getMonth() + 1, 0);
+
+ const startDate = startOfWeek(firstOfMonth);
+ startDate.setDate(startDate.getDate() - 7);
+
+ const endDate = endOfWeek(lastOfMonth);
+ endDate.setDate(endDate.getDate() + 7);
+
+ CalendarService.loadEvents(startDate, endDate);
+ }
+
+ onSelectedDateChanged: updateSelectedDateEvents()
+ Component.onCompleted: {
+ loadEventsForMonth();
+ updateSelectedDateEvents();
+ }
+
+ Connections {
+ function onEventsByDateChanged() {
+ updateSelectedDateEvents();
+ }
+
+ function onKhalAvailableChanged() {
+ if (CalendarService && CalendarService.khalAvailable) {
+ loadEventsForMonth();
+ }
+ updateSelectedDateEvents();
+ }
+
+ target: CalendarService
+ enabled: CalendarService !== null
+ }
+
+ radius: Theme.cornerRadius
+ color: Theme.withAlpha(Theme.surfaceContainerHigh, Theme.popupTransparency)
+ border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.05)
+ border.width: 1
+
+ Column {
+ anchors.fill: parent
+ anchors.margins: Theme.spacingM
+ spacing: Theme.spacingS
+
+ Item {
+ width: parent.width
+ height: 40
+ visible: showEventDetails
+
+ Rectangle {
+ width: 32
+ height: 32
+ anchors.verticalCenter: parent.verticalCenter
+ anchors.left: parent.left
+ anchors.leftMargin: Theme.spacingS
+ radius: Theme.cornerRadius
+ color: backButtonArea.containsMouse ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12) : "transparent"
+
+ DankIcon {
+ anchors.centerIn: parent
+ name: "arrow_back"
+ size: 14
+ color: Theme.primary
+ }
+
+ MouseArea {
+ id: backButtonArea
+ anchors.fill: parent
+ hoverEnabled: true
+ cursorShape: Qt.PointingHandCursor
+ onClicked: root.showEventDetails = false
+ }
+ }
+
+ StyledText {
+ anchors.left: parent.left
+ anchors.right: parent.right
+ anchors.leftMargin: 32 + Theme.spacingS * 2
+ anchors.rightMargin: Theme.spacingS
+ height: 40
+ anchors.verticalCenter: parent.verticalCenter
+ text: {
+ const dateStr = Qt.formatDate(selectedDate, "MMM d");
+ if (selectedDateEvents && selectedDateEvents.length > 0) {
+ const eventCount = selectedDateEvents.length === 1 ? I18n.tr("1 event") : selectedDateEvents.length + " " + I18n.tr("events");
+ return dateStr + " • " + eventCount;
+ }
+ return dateStr;
+ }
+ font.pixelSize: Theme.fontSizeMedium
+ color: Theme.surfaceText
+ font.weight: Font.Medium
+ verticalAlignment: Text.AlignVCenter
+ elide: Text.ElideRight
+ }
+ }
+
+ Row {
+ width: parent.width
+ height: 28
+ visible: !showEventDetails
+
+ Rectangle {
+ width: 28
+ height: 28
+ radius: Theme.cornerRadius
+ color: prevMonthArea.containsMouse ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12) : "transparent"
+
+ DankIcon {
+ anchors.centerIn: parent
+ name: "chevron_left"
+ size: 14
+ color: Theme.primary
+ }
+
+ MouseArea {
+ id: prevMonthArea
+ anchors.fill: parent
+ hoverEnabled: true
+ cursorShape: Qt.PointingHandCursor
+ onClicked: {
+ let newDate = new Date(calendarGrid.displayDate);
+ newDate.setMonth(newDate.getMonth() - 1);
+ calendarGrid.displayDate = newDate;
+ loadEventsForMonth();
+ }
+ }
+ }
+
+ StyledText {
+ width: parent.width - 56
+ height: 28
+ text: calendarGrid.displayDate.toLocaleDateString(I18n.locale(), "MMMM yyyy")
+ font.pixelSize: Theme.fontSizeMedium
+ color: Theme.surfaceText
+ font.weight: Font.Medium
+ horizontalAlignment: Text.AlignHCenter
+ verticalAlignment: Text.AlignVCenter
+ }
+
+ Rectangle {
+ width: 28
+ height: 28
+ radius: Theme.cornerRadius
+ color: nextMonthArea.containsMouse ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12) : "transparent"
+
+ DankIcon {
+ anchors.centerIn: parent
+ name: "chevron_right"
+ size: 14
+ color: Theme.primary
+ }
+
+ MouseArea {
+ id: nextMonthArea
+ anchors.fill: parent
+ hoverEnabled: true
+ cursorShape: Qt.PointingHandCursor
+ onClicked: {
+ let newDate = new Date(calendarGrid.displayDate);
+ newDate.setMonth(newDate.getMonth() + 1);
+ calendarGrid.displayDate = newDate;
+ loadEventsForMonth();
+ }
+ }
+ }
+ }
+
+ Row {
+ width: parent.width
+ height: parent.height - 28 - Theme.spacingS
+ visible: !showEventDetails
+ spacing: SettingsData.showWeekNumber ? Theme.spacingS : 0
+
+ Column {
+ id: weekNumberColumn
+ visible: SettingsData.showWeekNumber
+ width: SettingsData.showWeekNumber ? 28 : 0
+ height: parent.height
+ spacing: Theme.spacingS
+
+ Item {
+ width: parent.width
+ height: 18
+ }
+
+ Grid {
+ width: parent.width
+ height: parent.height - 18 - Theme.spacingS
+ columns: 1
+ rows: 6
+
+ Repeater {
+ model: 6
+ Rectangle {
+ width: parent.width
+ height: parent.height / 6
+ color: "transparent"
+
+ StyledText {
+ anchors.centerIn: parent
+ text: {
+ const rowDate = new Date(calendarGrid.firstDay);
+ rowDate.setDate(rowDate.getDate() + index * 7);
+ return root.getWeekNumber(rowDate);
+ }
+ font.pixelSize: Theme.fontSizeSmall
+ color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.6)
+ font.weight: Font.Medium
+ }
+ }
+ }
+ }
+ }
+
+ Column {
+ width: SettingsData.showWeekNumber ? (parent.width - weekNumberColumn.width - parent.spacing) : parent.width
+ height: parent.height
+ spacing: Theme.spacingS
+
+ Row {
+ width: parent.width
+ height: 18
+
+ Repeater {
+ model: {
+ const days = [];
+ const qtFirst = weekStartQt();
+ for (let i = 0; i < 7; ++i) {
+ const qtDay = ((qtFirst - 1 + i) % 7) + 1;
+ days.push(I18n.locale().dayName(qtDay, Locale.ShortFormat));
+ }
+ return days;
+ }
+
+ Rectangle {
+ width: parent.width / 7
+ height: 18
+ color: "transparent"
+
+ StyledText {
+ anchors.centerIn: parent
+ text: modelData
+ font.pixelSize: Theme.fontSizeSmall
+ color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.6)
+ font.weight: Font.Medium
+ }
+ }
+ }
+ }
+
+ Grid {
+ id: calendarGrid
+ width: parent.width
+ height: parent.height - 18 - Theme.spacingS
+ columns: 7
+ rows: 6
+
+ property date displayDate: systemClock.date
+ property date selectedDate: systemClock.date
+
+ readonly property date firstDay: {
+ const firstOfMonth = new Date(displayDate.getFullYear(), displayDate.getMonth(), 1);
+ return startOfWeek(firstOfMonth);
+ }
+
+ Repeater {
+ model: 42
+
+ Rectangle {
+ readonly property date dayDate: {
+ const date = new Date(parent.firstDay);
+ date.setDate(date.getDate() + index);
+ return date;
+ }
+ readonly property bool isCurrentMonth: dayDate.getMonth() === calendarGrid.displayDate.getMonth()
+ readonly property bool isToday: dayDate.toDateString() === new Date().toDateString()
+ readonly property bool isSelected: dayDate.toDateString() === calendarGrid.selectedDate.toDateString()
+
+ width: parent.width / 7
+ height: parent.height / 6
+ color: "transparent"
+
+ Rectangle {
+ anchors.centerIn: parent
+ width: Math.min(parent.width - 4, parent.height - 4, 32)
+ height: width
+ color: isToday ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12) : dayArea.containsMouse ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.08) : "transparent"
+ radius: Theme.cornerRadius
+
+ StyledText {
+ anchors.centerIn: parent
+ text: dayDate.getDate()
+ font.pixelSize: Theme.fontSizeSmall
+ color: isToday ? Theme.primary : isCurrentMonth ? Theme.surfaceText : Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.4)
+ font.weight: isToday ? Font.Medium : Font.Normal
+ }
+
+ Rectangle {
+ anchors.bottom: parent.bottom
+ anchors.horizontalCenter: parent.horizontalCenter
+ anchors.bottomMargin: 4
+ width: 12
+ height: 2
+ radius: Theme.cornerRadius
+ visible: CalendarService && CalendarService.khalAvailable && CalendarService.hasEventsForDate(dayDate)
+ color: isToday ? Qt.lighter(Theme.primary, 1.3) : Theme.primary
+ opacity: isToday ? 0.9 : 0.7
+
+ Behavior on opacity {
+ NumberAnimation {
+ duration: Theme.shortDuration
+ easing.type: Theme.standardEasing
+ }
+ }
+ }
+ }
+
+ MouseArea {
+ id: dayArea
+ anchors.fill: parent
+ hoverEnabled: true
+ cursorShape: Qt.PointingHandCursor
+ onClicked: {
+ if (CalendarService && CalendarService.khalAvailable && CalendarService.hasEventsForDate(dayDate)) {
+ root.selectedDate = dayDate;
+ root.showEventDetails = true;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ DankListView {
+ width: parent.width - Theme.spacingS * 2
+ height: parent.height - (showEventDetails ? 40 : 28 + 18) - Theme.spacingS
+ anchors.horizontalCenter: parent.horizontalCenter
+ model: selectedDateEvents
+ visible: showEventDetails
+ clip: true
+ spacing: Theme.spacingXS
+
+ delegate: Rectangle {
+ width: parent ? parent.width : 0
+ height: eventContent.implicitHeight + Theme.spacingS
+ radius: Theme.cornerRadius
+ color: {
+ if (modelData.url && eventMouseArea.containsMouse) {
+ return Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12);
+ } else if (eventMouseArea.containsMouse) {
+ return Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.06);
+ }
+ return Theme.withAlpha(Theme.surfaceContainerHigh, Theme.popupTransparency);
+ }
+ border.color: {
+ if (modelData.url && eventMouseArea.containsMouse) {
+ return Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.3);
+ } else if (eventMouseArea.containsMouse) {
+ return Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.15);
+ }
+ return "transparent";
+ }
+ border.width: 1
+
+ Rectangle {
+ width: 3
+ height: parent.height - 6
+ anchors.left: parent.left
+ anchors.leftMargin: 3
+ anchors.verticalCenter: parent.verticalCenter
+ radius: Theme.cornerRadius
+ color: Theme.primary
+ opacity: 0.8
+ }
+
+ Column {
+ id: eventContent
+
+ anchors.left: parent.left
+ anchors.right: parent.right
+ anchors.verticalCenter: parent.verticalCenter
+ anchors.leftMargin: Theme.spacingS + 6
+ anchors.rightMargin: Theme.spacingXS
+ spacing: 2
+
+ StyledText {
+ width: parent.width
+ text: modelData.title
+ font.pixelSize: Theme.fontSizeSmall
+ color: Theme.surfaceText
+ font.weight: Font.Medium
+ elide: Text.ElideRight
+ maximumLineCount: 1
+ }
+
+ StyledText {
+ width: parent.width
+ text: {
+ if (!modelData || modelData.allDay) {
+ return I18n.tr("All day");
+ } else if (modelData.start && modelData.end) {
+ const timeFormat = SettingsData.use24HourClock ? "HH:mm" : "h:mm AP";
+ const startTime = Qt.formatTime(modelData.start, timeFormat);
+ if (modelData.start.toDateString() !== modelData.end.toDateString() || modelData.start.getTime() !== modelData.end.getTime()) {
+ return startTime + " – " + Qt.formatTime(modelData.end, timeFormat);
+ }
+ return startTime;
+ }
+ return "";
+ }
+ font.pixelSize: Theme.fontSizeSmall
+ color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.7)
+ font.weight: Font.Normal
+ visible: text !== ""
+ }
+ }
+
+ MouseArea {
+ id: eventMouseArea
+
+ anchors.fill: parent
+ hoverEnabled: true
+ cursorShape: modelData.url ? Qt.PointingHandCursor : Qt.ArrowCursor
+ enabled: modelData.url !== ""
+ onClicked: {
+ if (modelData.url && modelData.url !== "") {
+ if (Qt.openUrlExternally(modelData.url) === false) {
+ console.warn("Failed to open URL: " + modelData.url);
+ } else {
+ root.closeDash();
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ SystemClock {
+ id: systemClock
+ precision: SystemClock.Hours
+ }
+}
diff --git a/raveos-hyprland-theme/theme-data/dms/Modules/DankDash/Overview/Card.qml b/raveos-hyprland-theme/theme-data/dms/Modules/DankDash/Overview/Card.qml
new file mode 100644
index 0000000..8996c81
--- /dev/null
+++ b/raveos-hyprland-theme/theme-data/dms/Modules/DankDash/Overview/Card.qml
@@ -0,0 +1,24 @@
+import QtQuick
+import qs.Common
+
+Rectangle {
+ id: card
+
+ LayoutMirroring.enabled: I18n.isRtl
+ LayoutMirroring.childrenInherit: true
+
+ property int pad: Theme.spacingM
+
+ radius: Theme.cornerRadius
+ color: Theme.withAlpha(Theme.surfaceContainerHigh, Theme.popupTransparency)
+ border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.08)
+ border.width: 1
+
+ default property alias content: contentItem.data
+
+ Item {
+ id: contentItem
+ anchors.fill: parent
+ anchors.margins: card.pad
+ }
+}
diff --git a/raveos-hyprland-theme/theme-data/dms/Modules/DankDash/Overview/ClockCard.qml b/raveos-hyprland-theme/theme-data/dms/Modules/DankDash/Overview/ClockCard.qml
new file mode 100644
index 0000000..5f597c3
--- /dev/null
+++ b/raveos-hyprland-theme/theme-data/dms/Modules/DankDash/Overview/ClockCard.qml
@@ -0,0 +1,113 @@
+import QtQuick
+import QtQuick.Effects
+import Quickshell
+import qs.Common
+import qs.Widgets
+
+Card {
+ id: root
+
+ Column {
+ anchors.centerIn: parent
+ spacing: 0
+
+ Column {
+ spacing: -8
+ anchors.horizontalCenter: parent.horizontalCenter
+
+ Row {
+ spacing: 0
+ anchors.horizontalCenter: parent.horizontalCenter
+
+ StyledText {
+ text: {
+ if (SettingsData.use24HourClock) {
+ return String(systemClock?.date?.getHours()).padStart(2, '0').charAt(0)
+ } else {
+ const hours = systemClock?.date?.getHours()
+ const display = hours === 0 ? 12 : hours > 12 ? hours - 12 : hours
+ return String(display).padStart(2, '0').charAt(0)
+ }
+ }
+ font.pixelSize: 48
+ color: Theme.primary
+ font.weight: Font.Medium
+ width: 28
+ horizontalAlignment: Text.AlignHCenter
+ }
+
+ StyledText {
+ text: {
+ if (SettingsData.use24HourClock) {
+ return String(systemClock?.date?.getHours()).padStart(2, '0').charAt(1)
+ } else {
+ const hours = systemClock?.date?.getHours()
+ const display = hours === 0 ? 12 : hours > 12 ? hours - 12 : hours
+ return String(display).padStart(2, '0').charAt(1)
+ }
+ }
+ font.pixelSize: 48
+ color: Theme.primary
+ font.weight: Font.Medium
+ width: 28
+ horizontalAlignment: Text.AlignHCenter
+ }
+ }
+
+ Row {
+ spacing: 0
+ anchors.horizontalCenter: parent.horizontalCenter
+
+ StyledText {
+ text: String(systemClock?.date?.getMinutes()).padStart(2, '0').charAt(0)
+ font.pixelSize: 48
+ color: Theme.primary
+ font.weight: Font.Medium
+ width: 28
+ horizontalAlignment: Text.AlignHCenter
+ }
+
+ StyledText {
+ text: String(systemClock?.date?.getMinutes()).padStart(2, '0').charAt(1)
+ font.pixelSize: 48
+ color: Theme.primary
+ font.weight: Font.Medium
+ width: 28
+ horizontalAlignment: Text.AlignHCenter
+ }
+ }
+ }
+
+ Row {
+ visible: SettingsData.showSeconds
+ spacing: 0
+ anchors.horizontalCenter: parent.horizontalCenter
+
+ StyledText {
+ text: String(systemClock?.date?.getSeconds()).padStart(2, '0')
+ font.pixelSize: 24
+ color: Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.7)
+ font.weight: Font.Medium
+ horizontalAlignment: Text.AlignHCenter
+ }
+ }
+
+ Item {
+ width: 1
+ height: Theme.spacingXS
+ anchors.horizontalCenter: parent.horizontalCenter
+ }
+
+ StyledText {
+ text: systemClock?.date?.toLocaleDateString(I18n.locale(), "MMM dd")
+ font.pixelSize: Theme.fontSizeSmall
+ color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.7)
+ anchors.horizontalCenter: parent.horizontalCenter
+ }
+ }
+
+ SystemClock {
+ id: systemClock
+ precision: SettingsData.showSeconds ? SystemClock.Seconds : SystemClock.Minutes
+ }
+}
diff --git a/raveos-hyprland-theme/theme-data/dms/Modules/DankDash/Overview/MediaOverviewCard.qml b/raveos-hyprland-theme/theme-data/dms/Modules/DankDash/Overview/MediaOverviewCard.qml
new file mode 100644
index 0000000..35f4f47
--- /dev/null
+++ b/raveos-hyprland-theme/theme-data/dms/Modules/DankDash/Overview/MediaOverviewCard.qml
@@ -0,0 +1,211 @@
+import QtQuick
+import QtQuick.Effects
+import QtQuick.Shapes
+import Quickshell.Services.Mpris
+import qs.Common
+import qs.Services
+import qs.Widgets
+
+Card {
+ id: root
+ clip: false
+
+ signal clicked()
+
+ property MprisPlayer activePlayer: MprisController.activePlayer
+ property real currentPosition: activePlayer?.positionSupported ? activePlayer.position : 0
+ property real displayPosition: currentPosition
+
+ readonly property real ratio: {
+ if (!activePlayer || activePlayer.length <= 0) return 0
+ const pos = displayPosition % Math.max(1, activePlayer.length)
+ const calculatedRatio = pos / activePlayer.length
+ return Math.max(0, Math.min(1, calculatedRatio))
+ }
+
+ onActivePlayerChanged: {
+ if (activePlayer?.positionSupported) {
+ currentPosition = Qt.binding(() => activePlayer?.position || 0)
+ } else {
+ currentPosition = 0
+ }
+ }
+
+ Timer {
+ interval: 300
+ running: activePlayer?.playbackState === MprisPlaybackState.Playing && !isSeeking
+ repeat: true
+ onTriggered: activePlayer?.positionSupported && activePlayer.positionChanged()
+ }
+
+ property bool isSeeking: false
+
+ Column {
+ anchors.centerIn: parent
+ spacing: Theme.spacingS
+ visible: !activePlayer
+
+ DankIcon {
+ name: "music_note"
+ size: Theme.iconSize
+ color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.5)
+ anchors.horizontalCenter: parent.horizontalCenter
+ }
+
+ StyledText {
+ text: I18n.tr("No Media")
+ font.pixelSize: Theme.fontSizeSmall
+ color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.7)
+ anchors.horizontalCenter: parent.horizontalCenter
+ }
+ }
+
+ Column {
+ anchors.centerIn: parent
+ width: parent.width - Theme.spacingXS * 2
+ spacing: Theme.spacingL
+ visible: activePlayer
+
+ Item {
+ width: 140
+ height: 110
+ anchors.horizontalCenter: parent.horizontalCenter
+ clip: false
+
+ DankAlbumArt {
+ width: 110
+ height: 80
+ anchors.centerIn: parent
+ activePlayer: root.activePlayer
+ albumSize: 76
+ animationScale: 1.05
+ }
+ }
+
+ Column {
+ width: parent.width
+ spacing: Theme.spacingXS
+ topPadding: Theme.spacingL
+
+ StyledText {
+ text: activePlayer?.trackTitle || I18n.tr("Unknown")
+ font.pixelSize: Theme.fontSizeSmall
+ font.weight: Font.Medium
+ color: Theme.surfaceText
+ width: parent.width
+ elide: Text.ElideRight
+ maximumLineCount: 1
+ horizontalAlignment: Text.AlignHCenter
+ }
+
+ StyledText {
+ text: activePlayer?.trackArtist || I18n.tr("Unknown Artist")
+ font.pixelSize: Theme.fontSizeSmall
+ color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.7)
+ width: parent.width
+ elide: Text.ElideRight
+ maximumLineCount: 1
+ horizontalAlignment: Text.AlignHCenter
+ }
+ }
+
+ DankSeekbar {
+ width: parent.width + 4
+ height: 20
+ x: -2
+ activePlayer: root.activePlayer
+ isSeeking: root.isSeeking
+ onIsSeekingChanged: root.isSeeking = isSeeking
+ }
+
+ Item {
+ width: parent.width
+ height: 32
+
+ Row {
+ spacing: Theme.spacingS
+ anchors.centerIn: parent
+
+ Rectangle {
+ width: 28
+ height: 28
+ radius: 14
+ anchors.verticalCenter: playPauseButton.verticalCenter
+ color: prevArea.containsMouse ? Theme.withAlpha(Theme.surfaceContainerHigh, Theme.popupTransparency) : "transparent"
+
+ DankIcon {
+ anchors.centerIn: parent
+ name: "skip_previous"
+ size: 14
+ color: Theme.surfaceText
+ }
+
+ MouseArea {
+ id: prevArea
+ anchors.fill: parent
+ hoverEnabled: true
+ cursorShape: Qt.PointingHandCursor
+ onClicked: MprisController.previousOrRewind()
+ }
+ }
+
+ Rectangle {
+ id: playPauseButton
+ width: 32
+ height: 32
+ radius: 16
+ color: Theme.primary
+
+ DankIcon {
+ anchors.centerIn: parent
+ name: activePlayer?.playbackState === MprisPlaybackState.Playing ? "pause" : "play_arrow"
+ size: 16
+ color: Theme.background
+ }
+
+ MouseArea {
+ anchors.fill: parent
+ hoverEnabled: true
+ cursorShape: Qt.PointingHandCursor
+ onClicked: activePlayer?.togglePlaying()
+ }
+ }
+
+ Rectangle {
+ width: 28
+ height: 28
+ radius: 14
+ anchors.verticalCenter: playPauseButton.verticalCenter
+ color: nextArea.containsMouse ? Theme.withAlpha(Theme.surfaceContainerHigh, Theme.popupTransparency) : "transparent"
+
+ DankIcon {
+ anchors.centerIn: parent
+ name: "skip_next"
+ size: 14
+ color: Theme.surfaceText
+ }
+
+ MouseArea {
+ id: nextArea
+ anchors.fill: parent
+ hoverEnabled: true
+ cursorShape: Qt.PointingHandCursor
+ onClicked: activePlayer?.next()
+ }
+ }
+ }
+ }
+ }
+
+ MouseArea {
+ anchors.top: parent.top
+ anchors.left: parent.left
+ anchors.right: parent.right
+ anchors.bottom: parent.bottom
+ anchors.bottomMargin: 123
+ hoverEnabled: true
+ cursorShape: Qt.PointingHandCursor
+ onClicked: root.clicked()
+ visible: activePlayer
+ }
+}
diff --git a/raveos-hyprland-theme/theme-data/dms/Modules/DankDash/Overview/SystemMonitorCard.qml b/raveos-hyprland-theme/theme-data/dms/Modules/DankDash/Overview/SystemMonitorCard.qml
new file mode 100644
index 0000000..cb7089b
--- /dev/null
+++ b/raveos-hyprland-theme/theme-data/dms/Modules/DankDash/Overview/SystemMonitorCard.qml
@@ -0,0 +1,178 @@
+import QtQuick
+import QtQuick.Effects
+import qs.Common
+import qs.Services
+import qs.Widgets
+
+Card {
+ id: root
+
+ Component.onCompleted: {
+ DgopService.addRef(["cpu", "memory", "system"])
+ }
+ Component.onDestruction: {
+ DgopService.removeRef(["cpu", "memory", "system"])
+ }
+
+ Row {
+ anchors.fill: parent
+ anchors.margins: Theme.spacingS
+ spacing: Theme.spacingM
+
+ // CPU Bar
+ Column {
+ width: (parent.width - 2 * Theme.spacingM) / 3
+ height: parent.height
+ spacing: Theme.spacingS
+
+ Rectangle {
+ width: 8
+ height: parent.height - Theme.iconSizeSmall - Theme.spacingS
+ radius: 4
+ anchors.horizontalCenter: parent.horizontalCenter
+ color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.2)
+
+ Rectangle {
+ width: parent.width
+ height: parent.height * Math.min((DgopService.cpuUsage || 6) / 100, 1)
+ radius: parent.radius
+ anchors.bottom: parent.bottom
+ anchors.horizontalCenter: parent.horizontalCenter
+ color: {
+ if (DgopService.cpuUsage > 80) return Theme.error
+ if (DgopService.cpuUsage > 60) return Theme.warning
+ return Theme.primary
+ }
+
+ Behavior on height {
+ NumberAnimation {
+ duration: Theme.shortDuration
+ easing.type: Theme.standardEasing
+ }
+ }
+ }
+ }
+
+ Item {
+ width: parent.width
+ height: Theme.iconSizeSmall
+
+ DankIcon {
+ name: "memory"
+ size: Theme.iconSizeSmall
+ anchors.horizontalCenter: parent.horizontalCenter
+ anchors.bottom: parent.bottom
+ color: {
+ if (DgopService.cpuUsage > 80) return Theme.error
+ if (DgopService.cpuUsage > 60) return Theme.warning
+ return Theme.primary
+ }
+ }
+ }
+ }
+
+ // Temperature Bar
+ Column {
+ width: (parent.width - 2 * Theme.spacingM) / 3
+ height: parent.height
+ spacing: Theme.spacingS
+
+ Rectangle {
+ width: 8
+ height: parent.height - Theme.iconSizeSmall - Theme.spacingS
+ radius: 4
+ anchors.horizontalCenter: parent.horizontalCenter
+ color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.2)
+
+ Rectangle {
+ width: parent.width
+ height: parent.height * Math.min(Math.max((DgopService.cpuTemperature || 40) / 100, 0), 1)
+ radius: parent.radius
+ anchors.bottom: parent.bottom
+ anchors.horizontalCenter: parent.horizontalCenter
+ color: {
+ if (DgopService.cpuTemperature > 85) return Theme.error
+ if (DgopService.cpuTemperature > 69) return Theme.warning
+ return Theme.primary
+ }
+
+ Behavior on height {
+ NumberAnimation {
+ duration: Theme.shortDuration
+ easing.type: Theme.standardEasing
+ }
+ }
+ }
+ }
+
+ Item {
+ width: parent.width
+ height: Theme.iconSizeSmall
+
+ DankIcon {
+ name: "device_thermostat"
+ size: Theme.iconSizeSmall
+ anchors.horizontalCenter: parent.horizontalCenter
+ anchors.bottom: parent.bottom
+ color: {
+ if (DgopService.cpuTemperature > 85) return Theme.error
+ if (DgopService.cpuTemperature > 69) return Theme.warning
+ return Theme.primary
+ }
+ }
+ }
+ }
+
+ // RAM Bar
+ Column {
+ width: (parent.width - 2 * Theme.spacingM) / 3
+ height: parent.height
+ spacing: Theme.spacingS
+
+ Rectangle {
+ width: 8
+ height: parent.height - Theme.iconSizeSmall - Theme.spacingS
+ radius: 4
+ anchors.horizontalCenter: parent.horizontalCenter
+ color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.2)
+
+ Rectangle {
+ width: parent.width
+ height: parent.height * Math.min((DgopService.memoryUsage || 42) / 100, 1)
+ radius: parent.radius
+ anchors.bottom: parent.bottom
+ anchors.horizontalCenter: parent.horizontalCenter
+ color: {
+ if (DgopService.memoryUsage > 90) return Theme.error
+ if (DgopService.memoryUsage > 75) return Theme.warning
+ return Theme.primary
+ }
+
+ Behavior on height {
+ NumberAnimation {
+ duration: Theme.shortDuration
+ easing.type: Theme.standardEasing
+ }
+ }
+ }
+ }
+
+ Item {
+ width: parent.width
+ height: Theme.iconSizeSmall
+
+ DankIcon {
+ name: "developer_board"
+ size: Theme.iconSizeSmall
+ anchors.horizontalCenter: parent.horizontalCenter
+ anchors.bottom: parent.bottom
+ color: {
+ if (DgopService.memoryUsage > 90) return Theme.error
+ if (DgopService.memoryUsage > 75) return Theme.warning
+ return Theme.primary
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/raveos-hyprland-theme/theme-data/dms/Modules/DankDash/Overview/UserInfoCard.qml b/raveos-hyprland-theme/theme-data/dms/Modules/DankDash/Overview/UserInfoCard.qml
new file mode 100644
index 0000000..0d90b44
--- /dev/null
+++ b/raveos-hyprland-theme/theme-data/dms/Modules/DankDash/Overview/UserInfoCard.qml
@@ -0,0 +1,110 @@
+import QtQuick
+import qs.Common
+import qs.Services
+import qs.Widgets
+
+Card {
+ id: root
+
+ LayoutMirroring.enabled: I18n.isRtl
+ LayoutMirroring.childrenInherit: true
+
+ Component.onCompleted: DgopService.addRef("system")
+ Component.onDestruction: DgopService.removeRef("system")
+
+ Row {
+ anchors.left: parent.left
+ anchors.leftMargin: Theme.spacingM
+ anchors.verticalCenter: parent.verticalCenter
+ spacing: Theme.spacingM
+
+ DankCircularImage {
+ id: avatarContainer
+
+ width: 77
+ height: 77
+ anchors.verticalCenter: parent.verticalCenter
+ imageSource: {
+ if (PortalService.profileImage === "")
+ return "";
+
+ if (PortalService.profileImage.startsWith("/"))
+ return "file://" + PortalService.profileImage;
+
+ return PortalService.profileImage;
+ }
+ fallbackIcon: "person"
+ }
+
+ Column {
+ spacing: Theme.spacingS
+ anchors.verticalCenter: parent.verticalCenter
+
+ StyledText {
+ text: UserInfoService.username || I18n.tr("brandon")
+ font.pixelSize: Theme.fontSizeLarge
+ font.weight: Font.Medium
+ color: Theme.surfaceText
+ elide: Text.ElideRight
+ width: parent.parent.parent.width - avatarContainer.width - Theme.spacingM * 3
+ horizontalAlignment: Text.AlignLeft
+ }
+
+ Row {
+ anchors.left: parent.left
+ spacing: Theme.spacingS
+
+ SystemLogo {
+ width: 16
+ height: 16
+ anchors.verticalCenter: parent.verticalCenter
+ colorOverride: Theme.primary
+ }
+
+ StyledText {
+ text: {
+ if (CompositorService.isNiri)
+ return I18n.tr("on Niri");
+ if (CompositorService.isHyprland)
+ return I18n.tr("on Hyprland");
+ // technically they might not be on mangowc, but its what we support in the docs
+ if (CompositorService.isDwl)
+ return I18n.tr("on MangoWC");
+ if (CompositorService.isSway)
+ return I18n.tr("on Sway");
+ if (CompositorService.isScroll)
+ return I18n.tr("on Scroll");
+ if (CompositorService.isMiracle)
+ return I18n.tr("on Miracle WM");
+ return "";
+ }
+ font.pixelSize: Theme.fontSizeSmall
+ color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.8)
+ anchors.verticalCenter: parent.verticalCenter
+ elide: Text.ElideRight
+ width: parent.parent.parent.parent.width - avatarContainer.width - Theme.spacingM * 3 - 16 - Theme.spacingS
+ horizontalAlignment: Text.AlignLeft
+ }
+ }
+
+ Row {
+ anchors.left: parent.left
+ spacing: Theme.spacingS
+
+ DankIcon {
+ name: "schedule"
+ size: 16
+ color: Theme.primary
+ anchors.verticalCenter: parent.verticalCenter
+ }
+
+ StyledText {
+ text: DgopService.shortUptime || I18n.tr("up")
+ font.pixelSize: Theme.fontSizeSmall
+ color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.7)
+ anchors.verticalCenter: parent.verticalCenter
+ }
+ }
+ }
+ }
+}
diff --git a/raveos-hyprland-theme/theme-data/dms/Modules/DankDash/Overview/WeatherOverviewCard.qml b/raveos-hyprland-theme/theme-data/dms/Modules/DankDash/Overview/WeatherOverviewCard.qml
new file mode 100644
index 0000000..0bba92e
--- /dev/null
+++ b/raveos-hyprland-theme/theme-data/dms/Modules/DankDash/Overview/WeatherOverviewCard.qml
@@ -0,0 +1,94 @@
+import QtQuick
+import QtQuick.Controls
+import qs.Common
+import qs.Services
+import qs.Widgets
+
+Card {
+ id: root
+
+ LayoutMirroring.enabled: I18n.isRtl
+ LayoutMirroring.childrenInherit: true
+
+ signal clicked
+
+ Component.onCompleted: WeatherService.addRef()
+ Component.onDestruction: WeatherService.removeRef()
+
+ Column {
+ anchors.centerIn: parent
+ spacing: Theme.spacingS
+ visible: !WeatherService.weather.available
+
+ DankIcon {
+ name: "cloud_off"
+ size: 24
+ color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.5)
+ anchors.horizontalCenter: parent.horizontalCenter
+ }
+
+ StyledText {
+ text: WeatherService.weather.loading ? I18n.tr("Loading...") : I18n.tr("No Weather")
+ font.pixelSize: Theme.fontSizeSmall
+ color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.7)
+ anchors.horizontalCenter: parent.horizontalCenter
+ }
+
+ Button {
+ text: I18n.tr("Refresh")
+ flat: true
+ visible: !WeatherService.weather.loading
+ anchors.horizontalCenter: parent.horizontalCenter
+ onClicked: WeatherService.forceRefresh()
+ }
+ }
+
+ Row {
+ anchors.left: parent.left
+ anchors.leftMargin: Theme.spacingL
+ anchors.verticalCenter: parent.verticalCenter
+ spacing: Theme.spacingL
+ visible: WeatherService.weather.available
+
+ DankIcon {
+ name: WeatherService.getWeatherIcon(WeatherService.weather.wCode)
+ size: 48
+ color: Theme.primary
+ anchors.verticalCenter: parent.verticalCenter
+ }
+
+ Column {
+ spacing: Theme.spacingXS
+ anchors.verticalCenter: parent.verticalCenter
+
+ StyledText {
+ anchors.left: parent.left
+ text: {
+ const temp = SettingsData.useFahrenheit ? WeatherService.weather.tempF : WeatherService.weather.temp;
+ if (temp === undefined || temp === null)
+ return "--°" + (SettingsData.useFahrenheit ? "F" : "C");
+ return temp + "°" + (SettingsData.useFahrenheit ? "F" : "C");
+ }
+ font.pixelSize: Theme.fontSizeXLarge + 4
+ color: Theme.surfaceText
+ font.weight: Font.Light
+ }
+
+ StyledText {
+ text: WeatherService.getWeatherCondition(WeatherService.weather.wCode)
+ font.pixelSize: Theme.fontSizeSmall
+ color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.7)
+ elide: Text.ElideRight
+ width: parent.parent.parent.width - 48 - Theme.spacingL * 2
+ horizontalAlignment: Text.AlignLeft
+ }
+ }
+ }
+
+ MouseArea {
+ anchors.fill: parent
+ hoverEnabled: true
+ cursorShape: Qt.PointingHandCursor
+ onClicked: root.clicked()
+ }
+}