SidePanel cards in a Cards directory

This commit is contained in:
quadbyte 2025-08-12 10:53:34 -04:00
parent 986eac179e
commit a11e310580
5 changed files with 1 additions and 0 deletions

View file

@ -0,0 +1,47 @@
import QtQuick
import QtQuick.Layouts
import qs.Services
import qs.Widgets
// Media player area (placeholder until MediaPlayer service is wired)
NBox {
id: root
readonly property real scaling: Scaling.scale(screen)
Layout.fillWidth: true
// Let content dictate the height (no hardcoded height here)
// Height can be overridden by parent layout (SidePanel binds it to stats card)
implicitHeight: content.implicitHeight + Style.marginLarge * 2 * scaling
Column {
id: content
anchors.left: parent.left
anchors.right: parent.right
anchors.top: parent.top
anchors.margins: Style.marginMedium * scaling
spacing: Style.marginMedium * scaling
Item {
height: Style.marginLarge * scaling
}
Text {
text: "music_note"
font.family: "Material Symbols Outlined"
font.pointSize: 28 * scaling
color: Colors.textSecondary
anchors.horizontalCenter: parent.horizontalCenter
}
NText {
text: "No music player detected"
color: Colors.textSecondary
horizontalAlignment: Text.AlignHCenter
anchors.horizontalCenter: parent.horizontalCenter
}
Item {
height: Style.marginLarge * scaling
}
}
}

View file

@ -0,0 +1,118 @@
import QtQuick
import QtQuick.Effects
import QtQuick.Layouts
import Quickshell
import Quickshell.Io
import Quickshell.Widgets
import qs.Services
import qs.Widgets
// Header card with avatar, user and quick actions
NBox {
id: root
readonly property real scaling: Scaling.scale(screen)
// Hold a single instance of the Settings window (root is NLoader)
property var settingsWindow: null
property string uptimeText: "--"
Layout.fillWidth: true
// Height driven by content
implicitHeight: content.implicitHeight + Style.marginMedium * 2 * scaling
RowLayout {
id: content
anchors.left: parent.left
anchors.right: parent.right
anchors.top: parent.top
anchors.margins: Style.marginMedium * scaling
spacing: Style.marginMedium * scaling
NImageRounded {
width: Style.baseWidgetSize * 1.25 * scaling
height: Style.baseWidgetSize * 1.25 * scaling
imagePath: Settings.data.general.avatarImage
fallbackIcon: "person"
borderColor: Colors.accentPrimary
borderWidth: Math.max(1, Style.borderMedium * scaling)
}
ColumnLayout {
Layout.fillWidth: true
spacing: 2 * scaling
NText {
text: Quickshell.env("USER") || "user"
font.weight: Style.fontWeightBold
}
NText {
text: `System Uptime: ${uptimeText}`
color: Colors.textSecondary
}
}
RowLayout {
spacing: Style.marginSmall * scaling
Layout.alignment: Qt.AlignRight | Qt.AlignVCenter
Item {
Layout.fillWidth: true
}
NIconButton {
icon: "settings"
onClicked: function () {
if (!root.settingsWindow) {
const comp = Qt.createComponent("../Settings/SettingsWindow.qml")
if (comp.status === Component.Ready) {
root.settingsWindow = comp.createObject(root)
} else {
comp.statusChanged.connect(function () {
if (comp.status === Component.Ready) {
root.settingsWindow = comp.createObject(root)
}
})
}
}
if (root.settingsWindow) {
root.settingsWindow.isLoaded = !root.settingsWindow.isLoaded
}
}
}
NIconButton {
icon: "power_settings_new"
}
}
}
Timer {
interval: 60000
repeat: true
running: true
onTriggered: uptimeProcess.running = true
}
Process {
id: uptimeProcess
command: ["cat", "/proc/uptime"]
running: true
stdout: StdioCollector {
onStreamFinished: {
var uptimeSeconds = parseFloat(this.text.trim().split(' ')[0])
var minutes = Math.floor(uptimeSeconds / 60) % 60
var hours = Math.floor(uptimeSeconds / 3600) % 24
var days = Math.floor(uptimeSeconds / 86400)
// Format the output
if (days > 0) {
uptimeText = days + "d " + hours + "h"
} else if (hours > 0) {
uptimeText = hours + "h" + minutes + "m"
} else {
uptimeText = minutes + "m"
}
uptimeProcess.running = false
}
}
}
}

View file

@ -0,0 +1,75 @@
import QtQuick
import QtQuick.Layouts
import qs.Services
import qs.Widgets
// Unified system card: monitors CPU, temp, memory, disk
NBox {
id: root
readonly property real scaling: Scaling.scale(screen)
Layout.preferredWidth: 84 * scaling
implicitHeight: content.implicitHeight + Style.marginTiny * 2 * scaling
Column {
id: content
anchors.left: parent.left
anchors.right: parent.right
anchors.top: parent.top
anchors.leftMargin: Style.marginSmall * scaling
anchors.rightMargin: Style.marginSmall * scaling
anchors.topMargin: Style.marginTiny * scaling
anchors.bottomMargin: Style.marginMedium * scaling
spacing: Style.marginSmall * scaling
// Slight top padding
Item {
height: Style.marginTiny * scaling
}
NSystemMonitor {
id: sysMon
intervalSeconds: 1
}
NCircleStat {
value: sysMon.cpuUsage || SysInfo.cpuUsage
icon: "speed"
flat: true
contentScale: 0.8
width: 72 * scaling
height: 68 * scaling
}
NCircleStat {
value: sysMon.cpuTemp || SysInfo.cpuTemp
suffix: "°C"
icon: "device_thermostat"
flat: true
contentScale: 0.8
width: 72 * scaling
height: 68 * scaling
}
NCircleStat {
value: sysMon.memoryUsagePer || SysInfo.memoryUsagePer
icon: "memory"
flat: true
contentScale: 0.8
width: 72 * scaling
height: 68 * scaling
}
NCircleStat {
value: sysMon.diskUsage || SysInfo.diskUsage
icon: "data_usage"
flat: true
contentScale: 0.8
width: 72 * scaling
height: 68 * scaling
}
// Extra bottom padding to shift the perceived stack slightly upward
Item {
height: Style.marginMedium * scaling
}
}
}

View file

@ -0,0 +1,121 @@
import QtQuick
import QtQuick.Layouts
import Quickshell
import qs.Services
import qs.Widgets
// Weather overview card (placeholder data)
NBox {
id: root
readonly property real scaling: Scaling.scale(screen)
readonly property bool weatherReady: (Location.data.weather !== null)
Layout.fillWidth: true
// Height driven by content
implicitHeight: content.implicitHeight + Style.marginLarge * 2 * scaling
ColumnLayout {
id: content
anchors.left: parent.left
anchors.right: parent.right
anchors.top: parent.top
anchors.margins: Style.marginMedium * scaling
spacing: Style.marginMedium * scaling
RowLayout {
spacing: Style.marginSmall * scaling
NText {
text: weatherReady ? Location.weatherSymbolFromCode(Location.data.weather.current_weather.weathercode) : ""
font.family: "Material Symbols Outlined"
font.pointSize: Style.fontSizeXXL * 1.25 * scaling
color: Colors.accentSecondary
}
ColumnLayout {
NText {
text: Settings.data.location.name
font.weight: Style.fontWeightBold
font.pointSize: Style.fontSizeXL * scaling
}
RowLayout {
NText {
visible: weatherReady
text: {
if (!weatherReady) {
return ""
}
var temp = Location.data.weather.current_weather.temperature
if (Settings.data.location.useFahrenheit) {
temp = Location.celsiusToFahrenheit(temp)
}
temp = Math.round(temp)
return `${temp}°`
}
font.pointSize: Style.fontSizeXL * scaling
font.weight: Style.fontWeightBold
}
NText {
text: weatherReady ? `(${Location.data.weather.timezone_abbreviation})` : ""
font.pointSize: Style.fontSizeSmall * scaling
visible: Location.data.weather
}
}
}
}
NDivider {
visible: weatherReady
Layout.fillWidth: true
}
RowLayout {
visible: weatherReady
Layout.fillWidth: true
Layout.alignment: Qt.AlignHCenter
spacing: Style.marginLarge * scaling
Repeater {
model: weatherReady ? Location.data.weather.daily.time : []
delegate: ColumnLayout {
Layout.alignment: Qt.AlignHCenter
spacing: Style.marginSmall * scaling
NText {
text: Qt.formatDateTime(new Date(Location.data.weather.daily.time[index]), "ddd")
color: Colors.textPrimary
}
NText {
text: Location.weatherSymbolFromCode(Location.data.weather.daily.weathercode[index])
font.family: "Material Symbols Outlined"
font.pointSize: Style.fontSizeXL * scaling
color: Colors.textSecondary
}
NText {
text: {
var max = Location.data.weather.daily.temperature_2m_max[index]
var min = Location.data.weather.daily.temperature_2m_min[index]
if (Settings.data.location.useFahrenheit) {
max = Location.celsiusToFahrenheit(max)
min = Location.celsiusToFahrenheit(min)
}
max = Math.round(max)
min = Math.round(min)
return `${max}°/${min}°`
}
font.pointSize: Style.fontSizeSmall * scaling
color: Colors.textSecondary
}
}
}
}
RowLayout {
visible: !weatherReady
Layout.fillWidth: true
Layout.alignment: Qt.AlignHCenter
NBusyIndicator {}
}
}
}