pragma ComponentBehavior: Bound import Quickshell import Quickshell.Hyprland import Quickshell.Wayland import QtQuick import QtQuick.Layouts import QtQuick.Shapes import qs.widgets.theme // Host vitals HUD — the "Slant" language (chamfered panel, trapezoid bevels, // outward corner chunks, floating cap, slanted dividers) carried over from the // sidebar and launcher V6, wrapped around this box's own node_exporter feed. // Toggled with SUPER CTRL V. Scope { id: root property bool active: false function toggle() { root.active = !root.active; } GlobalShortcut { name: "vitals" description: "Toggle the host vitals panel" onPressed: root.toggle() } VitalsData { id: vitals active: root.active } PanelWindow { id: win visible: root.active WlrLayershell.layer: WlrLayer.Overlay WlrLayershell.keyboardFocus: WlrKeyboardFocus.Exclusive // Ignore the bars' exclusive zones so the backdrop covers the screen. exclusionMode: ExclusionMode.Ignore color: "transparent" anchors { top: true left: true right: true bottom: true } onVisibleChanged: { if (visible) keys.forceActiveFocus(); } // Dim backdrop — click anywhere to dismiss. Rectangle { anchors.fill: parent color: Theme.surface opacity: 0.5 MouseArea { anchors.fill: parent onClicked: root.active = false } } Item { id: keys anchors.fill: parent focus: true Keys.onPressed: event => { if (event.key === Qt.Key_Escape) { root.active = false; event.accepted = true; } } } Item { id: frame anchors.centerIn: parent width: 620 height: content.implicitHeight + 2 * 26 readonly property int chamfer: 18 readonly property int bevel: 4 // inward thickness of the bevel borders readonly property int chunkThick: 8 // outward thickness of the heavy chunks readonly property int chunkSlant: 12 // slant of their end pieces readonly property int capSize: 10 // floating triangle cap readonly property int smallChamfer: 6 // Chamfered panel — top-left / bottom-right cut, accent edge. Shape { id: panelShape anchors.fill: parent preferredRendererType: Shape.CurveRenderer ShapePath { fillColor: Theme.surface strokeColor: Theme.accent strokeWidth: 2 startX: frame.chamfer startY: 0 PathLine { x: panelShape.width - frame.smallChamfer; y: 0 } PathLine { x: panelShape.width; y: frame.smallChamfer } PathLine { x: panelShape.width; y: panelShape.height - frame.chamfer } PathLine { x: panelShape.width - frame.chamfer; y: panelShape.height } PathLine { x: frame.smallChamfer; y: panelShape.height } PathLine { x: 0; y: panelShape.height - frame.smallChamfer } PathLine { x: 0; y: frame.chamfer } PathLine { x: frame.chamfer; y: 0 } } // Thick top-left bevel accent. ShapePath { strokeWidth: 0 fillColor: Theme.accent startX: 0 startY: frame.chamfer PathLine { x: frame.chamfer; y: 0 } PathLine { x: frame.chamfer + 2 * frame.bevel; y: 0 } PathLine { x: 0; y: frame.chamfer + 2 * frame.bevel } PathLine { x: 0; y: frame.chamfer } } // Thick bottom-right bevel accent. ShapePath { strokeWidth: 0 fillColor: Theme.accent startX: panelShape.width startY: panelShape.height - frame.chamfer PathLine { x: panelShape.width - frame.chamfer; y: panelShape.height } PathLine { x: panelShape.width - frame.chamfer - 2 * frame.bevel; y: panelShape.height } PathLine { x: panelShape.width; y: panelShape.height - frame.chamfer - 2 * frame.bevel } PathLine { x: panelShape.width; y: panelShape.height - frame.chamfer } } // Floating triangle cap in the bottom-right notch. ShapePath { strokeWidth: 0 fillColor: Theme.accent startX: panelShape.width startY: panelShape.height PathLine { x: panelShape.width; y: panelShape.height - frame.capSize } PathLine { x: panelShape.width - frame.capSize; y: panelShape.height } PathLine { x: panelShape.width; y: panelShape.height } } // Heavy outward chunk wrapping the bottom-left corner. ShapePath { strokeWidth: 0 fillColor: Theme.accent startX: panelShape.width / 3 startY: panelShape.height PathLine { x: panelShape.width / 3 - frame.chunkSlant; y: panelShape.height + frame.chunkThick } PathLine { x: frame.smallChamfer; y: panelShape.height + frame.chunkThick } PathLine { x: -frame.chunkThick; y: panelShape.height - frame.smallChamfer } PathLine { x: -frame.chunkThick; y: panelShape.height - panelShape.height / 7 + frame.chunkSlant } PathLine { x: 0; y: panelShape.height - panelShape.height / 7 } PathLine { x: 0; y: panelShape.height - frame.smallChamfer } PathLine { x: frame.smallChamfer; y: panelShape.height } PathLine { x: panelShape.width / 3; y: panelShape.height } } // Heavy outward chunk wrapping the top-right corner. ShapePath { strokeWidth: 0 fillColor: Theme.accent startX: panelShape.width startY: panelShape.height / 3 PathLine { x: panelShape.width + frame.chunkThick; y: panelShape.height / 3 - frame.chunkSlant } PathLine { x: panelShape.width + frame.chunkThick; y: frame.smallChamfer } PathLine { x: panelShape.width - frame.smallChamfer; y: -frame.chunkThick } PathLine { x: panelShape.width - panelShape.width / 5 + frame.chunkSlant; y: -frame.chunkThick } PathLine { x: panelShape.width - panelShape.width / 5; y: 0 } PathLine { x: panelShape.width - frame.smallChamfer; y: 0 } PathLine { x: panelShape.width; y: frame.smallChamfer } PathLine { x: panelShape.width; y: panelShape.height / 3 } } } // ── Content ──────────────────────────────────────────────────── ColumnLayout { id: content anchors.left: parent.left anchors.right: parent.right anchors.top: parent.top anchors.topMargin: 26 anchors.leftMargin: 30 anchors.rightMargin: 26 spacing: 12 // Header — slash trio, host, uptime. RowLayout { Layout.fillWidth: true spacing: 12 Shape { id: slashes implicitWidth: 26 implicitHeight: 22 Layout.alignment: Qt.AlignVCenter preferredRendererType: Shape.CurveRenderer ShapePath { strokeWidth: 0 fillColor: Theme.accent startX: 6 startY: 0 PathLine { x: 10; y: 0 } PathLine { x: 4; y: slashes.height } PathLine { x: 0; y: slashes.height } PathLine { x: 6; y: 0 } } ShapePath { strokeWidth: 0 fillColor: Theme.accent startX: 15 startY: 0 PathLine { x: 19; y: 0 } PathLine { x: 13; y: slashes.height } PathLine { x: 9; y: slashes.height } PathLine { x: 15; y: 0 } } ShapePath { strokeWidth: 0 fillColor: Theme.accent startX: 24 startY: 0 PathLine { x: 28; y: 0 } PathLine { x: 22; y: slashes.height } PathLine { x: 18; y: slashes.height } PathLine { x: 24; y: 0 } } } Text { text: (vitals.host || "vitals").toUpperCase() color: Theme.text font.family: Theme.readoutFont font.pointSize: 20 font.letterSpacing: 2 } Item { Layout.fillWidth: true } Text { text: "UP" color: Theme.muted font.family: Theme.readoutFont font.pointSize: 11 } Text { text: vitals.fmtUptime(vitals.uptime) color: Theme.accent font.family: Theme.readoutFont font.pointSize: 16 } } Slant {} // Unreachable exporter — say so rather than drawing zeroes. Text { Layout.fillWidth: true visible: vitals.failed text: "NODE_EXPORTER UNREACHABLE ON :" + vitals.port color: Theme.hot font.family: Theme.readoutFont font.pointSize: 13 } ColumnLayout { Layout.fillWidth: true visible: !vitals.failed spacing: 12 Metric { label: "CPU" value: vitals.cpu unknown: !vitals.ratesReady warn: 0.9 readout: vitals.ratesReady ? Math.round(vitals.cpu * 100) + "%" : "--" detail: "LOAD " + vitals.load1.toFixed(2) + " / " + vitals.load5.toFixed(2) + " / " + vitals.load15.toFixed(2) aside: vitals.cpuThreads + "T " + vitals.fmtTemp(vitals.cpuTemp) asideHot: vitals.cpuTemp >= 85 } Metric { label: "MEM" value: vitals.memTotal > 0 ? vitals.memUsed / vitals.memTotal : 0 unknown: !vitals.ready readout: vitals.memTotal > 0 ? Math.round(vitals.memUsed / vitals.memTotal * 100) + "%" : "--" detail: vitals.fmtBytes(vitals.memUsed) + " / " + vitals.fmtBytes(vitals.memTotal) aside: "" } // No GPU-busy counter exists in node_exporter, so the bar // tracks power draw against the card's cap — a real // reading, labelled for what it is rather than faked as // utilisation. Metric { label: "GPU" visible: isFinite(vitals.gpuTemp) value: isFinite(vitals.gpuPower) && vitals.gpuPowerCap > 0 ? vitals.gpuPower / vitals.gpuPowerCap : 0 unknown: !isFinite(vitals.gpuPower) warn: 0.9 readout: isFinite(vitals.gpuPower) ? Math.round(vitals.gpuPower) + "W" : "--" detail: (vitals.gpuPowerCap > 0 ? "CAP " + Math.round(vitals.gpuPowerCap) + "W" : "") + (isFinite(vitals.gpuClock) ? " SCLK " + Math.round(vitals.gpuClock) + " MHZ" : "") aside: vitals.fmtTemp(vitals.gpuTemp) + (isFinite(vitals.gpuHotspot) ? " / " + vitals.fmtTemp(vitals.gpuHotspot) : "") asideHot: vitals.gpuHotspot >= 95 } } Slant { visible: !vitals.failed } // Disks. ColumnLayout { Layout.fillWidth: true visible: !vitals.failed spacing: 6 Repeater { model: vitals.disks delegate: RowLayout { id: diskRow required property var modelData readonly property real frac: diskRow.modelData.size > 0 ? diskRow.modelData.used / diskRow.modelData.size : 0 Layout.fillWidth: true spacing: 12 Text { Layout.preferredWidth: 96 text: diskRow.modelData.mount color: Theme.muted font.pointSize: 9 elide: Text.ElideMiddle } VitalBar { Layout.fillWidth: true implicitHeight: 11 value: diskRow.frac warn: 0.9 } Text { Layout.preferredWidth: 48 horizontalAlignment: Text.AlignRight text: Math.round(diskRow.frac * 100) + "%" color: diskRow.frac >= 0.9 ? Theme.hot : Theme.text font.family: Theme.readoutFont font.pointSize: 13 } Text { Layout.preferredWidth: 104 horizontalAlignment: Text.AlignRight text: vitals.fmtBytes(diskRow.modelData.size - diskRow.modelData.used) + " FREE" color: Theme.muted font.family: Theme.readoutFont font.pointSize: 11 } } } } Slant { visible: !vitals.failed } // Network. RowLayout { Layout.fillWidth: true visible: !vitals.failed spacing: 12 Text { Layout.preferredWidth: 96 text: vitals.netIface || "NET" color: Theme.muted font.pointSize: 9 } Text { text: "RX" color: Theme.muted font.family: Theme.readoutFont font.pointSize: 11 } Text { text: vitals.fmtRate(vitals.netRx) color: Theme.accent font.family: Theme.readoutFont font.pointSize: 14 } Item { Layout.fillWidth: true } Text { text: "TX" color: Theme.muted font.family: Theme.readoutFont font.pointSize: 11 } Text { text: vitals.fmtRate(vitals.netTx) color: Theme.accent font.family: Theme.readoutFont font.pointSize: 14 // Right-align the TX readout against the panel edge the // disk rows' "FREE" column already lines up with. Layout.preferredWidth: 104 horizontalAlignment: Text.AlignRight } } } } } // ── Local pieces ─────────────────────────────────────────────────────── // A labelled bar with a readout, a sub-line and a right-hand aside. component Metric: ColumnLayout { id: metric property string label: "" property string readout: "" property string detail: "" property string aside: "" property bool asideHot: false property real value: 0 property real warn: 0.85 property bool unknown: false Layout.fillWidth: true spacing: 3 RowLayout { Layout.fillWidth: true spacing: 12 Text { Layout.preferredWidth: 46 text: metric.label color: Theme.accent font.family: Theme.readoutFont font.pointSize: 15 font.letterSpacing: 1 } VitalBar { Layout.fillWidth: true value: metric.value warn: metric.warn unknown: metric.unknown } Text { Layout.preferredWidth: 54 horizontalAlignment: Text.AlignRight text: metric.readout color: Theme.text font.family: Theme.readoutFont font.pointSize: 16 } } RowLayout { Layout.fillWidth: true Layout.leftMargin: 58 spacing: 12 Text { text: metric.detail color: Theme.muted font.family: Theme.readoutFont font.pointSize: 11 } Item { Layout.fillWidth: true } Text { visible: metric.aside.length > 0 text: metric.aside color: metric.asideHot ? Theme.hot : Theme.muted font.family: Theme.readoutFont font.pointSize: 11 } } } // Slanted divider — the launcher/sidebar motif. component Slant: Item { Layout.fillWidth: true implicitHeight: 3 Shape { id: divider anchors.fill: parent preferredRendererType: Shape.CurveRenderer ShapePath { strokeWidth: 0 fillColor: Theme.accent startX: 6 startY: 0 PathLine { x: divider.width; y: 0 } PathLine { x: divider.width - 6; y: divider.height } PathLine { x: 0; y: divider.height } PathLine { x: 6; y: 0 } } } } }