import "nix" import "one.krantz.rshell" import Quickshell import Quickshell.Io import Quickshell.Widgets import Quickshell.Hyprland import Quickshell.Services.UPower import QtQuick import QtQuick.Layouts import QtQuick.Controls import QtQuick.Shapes Variants { model: Quickshell.screens PanelWindow { id: panel // the screen from the screens list will be injected into this // property required property var modelData // we can then set the window's screen to the injected property screen: modelData anchors.top: true anchors.left: true anchors.right: true implicitHeight: 36 margins.top: 7 margins.left: 7 margins.right: 7 color: "transparent" Rectangle { id: bar anchors.fill: parent radius: 7 color: Theme.bg // Left section Pane { anchors.top: parent.top anchors.bottom: parent.bottom anchors.left: parent.left topPadding: 0 bottomPadding: 0 leftPadding: 10 rightPadding: 10 background: Rectangle { radius: bar.radius color: Theme.containerBg } RowLayout { anchors.fill: parent spacing: 10 Text { id: clock Layout.fillHeight: true verticalAlignment: Text.AlignVCenter horizontalAlignment: Text.AlignHCenter color: Theme.text font.bold: true text: Time.time } Rectangle { Layout.fillHeight: true width: 3 color: Theme.divider } Text { id: codedirstat Layout.fillHeight: true verticalAlignment: Text.AlignVCenter horizontalAlignment: Text.AlignHCenter color: Theme.text font.bold: true text: `${CodeDirStat.files}󰈔 ${CodeDirStat.commits}󰅟 ${CodeDirStat.stashes}` } } } // Center section RowLayout { anchors.top: parent.top anchors.bottom: parent.bottom anchors.horizontalCenter: parent.horizontalCenter anchors.leftMargin: 10 anchors.rightMargin: 10 spacing: 10 Repeater { model: 6 Rectangle { id: workspace required property int index readonly property HyprlandWorkspace ws: { Hyprland.workspaces.values.find(ws => ws.id === index + 1); } width: 16 height: width radius: width * 0.5 border.width: 3 border.color: Theme.inactive color: "transparent" states: [ State { name: "active-current" when: (workspace.ws && workspace.ws.active && workspace.ws.monitor.name === panel.screen.name) PropertyChanges { target: workspace color: workspace.border.color border.color: Theme.accent } }, State { name: "active-other" when: (workspace.ws && workspace.ws.active) PropertyChanges { target: workspace color: workspace.border.color border.color: Theme.fg } }, State { name: "current" when: (workspace.ws && workspace.ws.monitor.name === panel.screen.name) PropertyChanges { target: workspace border.color: Theme.accent } }, State { name: "other" when: (workspace.ws) PropertyChanges { target: workspace border.color: Theme.fg } } ] transitions: Transition { ParallelAnimation { ColorAnimation { target: workspace property: "color" duration: 500 easing.type: Easing.InOutQuad } ColorAnimation { target: workspace.border property: "color" duration: 500 easing.type: Easing.InOutQuad } } } } } } // Right section Pane { anchors.top: parent.top anchors.bottom: parent.bottom anchors.right: parent.right topPadding: 0 bottomPadding: 0 leftPadding: 10 rightPadding: 10 background: Rectangle { radius: bar.radius color: Theme.containerBg } RowLayout { anchors.fill: parent spacing: 10 Item { id: batteryIcon property UPowerDevice battery: UPower.displayDevice visible: battery.isPresent width: 60 height: 30 property real borderWidth: 3 scale: 2 / 3 // Properties property color lowColor: Theme.bad property color mediumColor: Theme.ok property color highColor: Theme.good property color borderColor: Theme.fg // Calculate fill color based on level property color fillColor: { if (battery.percentage <= 0.15) return lowColor; if (battery.percentage <= 0.4) return mediumColor; return highColor; } // Battery body with border Rectangle { id: batteryBody anchors.fill: parent color: "transparent" border.color: batteryIcon.borderColor border.width: batteryIcon.borderWidth radius: 7 // Fill progress bar Rectangle { id: fillBar anchors { left: parent.left top: parent.top bottom: parent.bottom margins: batteryIcon.borderWidth + 2 } width: Math.max(0, (parent.width - 2 * batteryIcon.borderWidth) * batteryIcon.battery.percentage) color: batteryIcon.fillColor radius: 2 // Smooth animation for level changes Behavior on width { NumberAnimation { duration: 1000 easing.type: Easing.OutCubic } } // Color transition animation Behavior on color { ColorAnimation { duration: 500 } } } } // Battery positive terminal (nub) Rectangle { id: batteryNub anchors { left: batteryBody.right verticalCenter: batteryBody.verticalCenter } width: 6 height: 12 color: batteryIcon.borderColor radius: 1 } // Lightning bolt (visible when charging) Shape { id: lightningBolt anchors.centerIn: batteryBody width: 14 height: 20 scale: 0.8 visible: batteryIcon.battery.state === UPowerDeviceState.Charging || batteryIcon.battery.state === UPowerDeviceState.FullyCharged || batteryIcon.battery.state === UPowerDeviceState.PendingCharge opacity: batteryIcon.battery.state === UPowerDeviceState.FullyCharged || batteryIcon.battery.state === UPowerDeviceState.PendingCharge ? 100 : 0 // Pulsing animation SequentialAnimation on opacity { running: batteryIcon.battery.state === UPowerDeviceState.Charging loops: Animation.Infinite NumberAnimation { to: 1 duration: 400 } NumberAnimation { to: 0.4 duration: 400 } } ShapePath { strokeWidth: 1 fillColor: batteryIcon.borderColor startX: 5 startY: 20 PathLine { x: 14 y: 8 } PathLine { x: 7 y: 8 } PathLine { x: 11 y: 0 } PathLine { x: 7 y: 0 } PathLine { x: 0 y: 12 } PathLine { x: 7 y: 12 } PathLine { x: 5 y: 20 } } } } } } } } }