533 lines
18 KiB
QML
533 lines
18 KiB
QML
import QtQuick
|
|
import QtQuick.Layouts
|
|
import Quickshell
|
|
import Quickshell.Hyprland
|
|
import Quickshell.Wayland
|
|
import "../theme"
|
|
import ".."
|
|
|
|
PanelWindow {
|
|
id: root
|
|
property var screen
|
|
|
|
WlrLayershell.layer: WlrLayer.Top
|
|
WlrLayershell.namespace: "quickshell-sidepanel"
|
|
WlrLayershell.keyboardFocus: WlrKeyboardFocus.None
|
|
|
|
anchors {
|
|
top: true
|
|
bottom: true
|
|
left: true
|
|
right: false
|
|
}
|
|
|
|
exclusiveZone: Theme.sidebarWidth
|
|
implicitWidth: Theme.sidebarWidth
|
|
color: Theme.bgPrimary
|
|
|
|
// Right edge hairline border
|
|
Rectangle {
|
|
width: 1
|
|
color: Theme.glassBorder
|
|
anchors {
|
|
right: parent.right
|
|
top: parent.top
|
|
bottom: parent.bottom
|
|
}
|
|
}
|
|
|
|
component Separator: Rectangle {
|
|
width: 36
|
|
height: 1
|
|
color: Theme.glassBorder
|
|
Layout.alignment: Qt.AlignHCenter
|
|
}
|
|
|
|
component DockIcon: Item {
|
|
id: dockIconRoot
|
|
width: 36
|
|
height: 36
|
|
Layout.alignment: Qt.AlignHCenter
|
|
|
|
property string appClass: ""
|
|
property string execCmd: ""
|
|
property string iconSource: ""
|
|
property string tooltipText: ""
|
|
|
|
property bool isRunning: (appClass !== "" && GlobalState.activeWindowClass === appClass) || (GlobalState.runningApps && GlobalState.runningApps.indexOf(appClass) !== -1)
|
|
|
|
Image {
|
|
id: img
|
|
anchors.centerIn: parent
|
|
width: 24
|
|
height: 24
|
|
source: iconSource ? Qt.resolvedUrl("../assets/" + iconSource) : ""
|
|
sourceSize: Qt.size(24, 24)
|
|
fillMode: Image.PreserveAspectFit
|
|
opacity: mouseArea.containsMouse ? 1.0 : 0.8
|
|
|
|
scale: mouseArea.containsMouse ? 1.15 : 1.0
|
|
Behavior on scale {
|
|
NumberAnimation { duration: Theme.animFast; easing.type: Easing.OutCubic }
|
|
}
|
|
Behavior on opacity {
|
|
NumberAnimation { duration: Theme.animFast; easing.type: Easing.OutCubic }
|
|
}
|
|
}
|
|
|
|
Rectangle {
|
|
id: runningDot
|
|
width: 4
|
|
height: 4
|
|
radius: 2
|
|
color: Theme.accentVolt
|
|
anchors.bottom: parent.bottom
|
|
anchors.horizontalCenter: parent.horizontalCenter
|
|
visible: isRunning
|
|
}
|
|
|
|
MouseArea {
|
|
id: mouseArea
|
|
anchors.fill: parent
|
|
hoverEnabled: true
|
|
onClicked: {
|
|
if (execCmd !== "") {
|
|
GlobalState.launchApp(execCmd)
|
|
}
|
|
}
|
|
}
|
|
|
|
// Tooltip
|
|
Rectangle {
|
|
id: tooltip
|
|
visible: mouseArea.containsMouse && tooltipText !== ""
|
|
color: Theme.glassBg
|
|
radius: 4
|
|
width: tooltipLabel.implicitWidth + 16
|
|
height: tooltipLabel.implicitHeight + 8
|
|
|
|
anchors.left: parent.right
|
|
anchors.leftMargin: 24
|
|
anchors.verticalCenter: parent.verticalCenter
|
|
|
|
Text {
|
|
id: tooltipLabel
|
|
anchors.centerIn: parent
|
|
text: tooltipText
|
|
color: Theme.textPrimary
|
|
font.family: Theme.fontSans
|
|
font.pixelSize: 11
|
|
}
|
|
}
|
|
}
|
|
|
|
ColumnLayout {
|
|
anchors.fill: parent
|
|
spacing: 8
|
|
|
|
// Top spacer
|
|
Item { height: 4; Layout.fillWidth: true }
|
|
|
|
// 1. AG Logo Button
|
|
Rectangle {
|
|
width: 36
|
|
height: 36
|
|
radius: 4
|
|
color: logoMouse.containsMouse ? Qt.rgba(1,1,1,0.05) : "transparent"
|
|
Layout.alignment: Qt.AlignHCenter
|
|
|
|
Behavior on color {
|
|
ColorAnimation { duration: Theme.animFast; easing.type: Easing.OutCubic }
|
|
}
|
|
|
|
Text {
|
|
anchors.centerIn: parent
|
|
text: "AG"
|
|
font.family: Theme.fontSerif
|
|
font.italic: true
|
|
font.pixelSize: 16
|
|
color: Theme.accentVolt
|
|
}
|
|
|
|
MouseArea {
|
|
id: logoMouse
|
|
anchors.fill: parent
|
|
hoverEnabled: true
|
|
onClicked: GlobalState.appleMenuVisible = !GlobalState.appleMenuVisible
|
|
}
|
|
}
|
|
|
|
Separator {}
|
|
|
|
// 3. Workspace Indicators
|
|
Column {
|
|
Layout.alignment: Qt.AlignHCenter
|
|
spacing: 2
|
|
|
|
Repeater {
|
|
model: GlobalState.workspaceList
|
|
delegate: Rectangle {
|
|
width: 52
|
|
height: 36
|
|
color: wsMouse.containsMouse ? Qt.rgba(1,1,1,0.04) : "transparent"
|
|
|
|
property bool isActive: GlobalState.activeWorkspace === modelData
|
|
|
|
Behavior on color {
|
|
ColorAnimation { duration: Theme.animFast; easing.type: Easing.OutCubic }
|
|
}
|
|
|
|
Rectangle {
|
|
width: 2
|
|
height: 20
|
|
anchors.left: parent.left
|
|
anchors.verticalCenter: parent.verticalCenter
|
|
color: Theme.accentVolt
|
|
visible: isActive
|
|
}
|
|
|
|
Column {
|
|
anchors.centerIn: parent
|
|
spacing: 2
|
|
|
|
Text {
|
|
anchors.horizontalCenter: parent.horizontalCenter
|
|
text: (modelData < 10 ? "0" : "") + modelData
|
|
color: isActive ? Theme.accentVolt : Theme.textMuted
|
|
font.family: Theme.fontMono
|
|
font.pixelSize: 12
|
|
|
|
Behavior on color {
|
|
ColorAnimation { duration: Theme.animFast; easing.type: Easing.OutCubic }
|
|
}
|
|
}
|
|
|
|
Text {
|
|
anchors.horizontalCenter: parent.horizontalCenter
|
|
text: (GlobalState.workspaceNames && GlobalState.workspaceNames[modelData]) ? GlobalState.workspaceNames[modelData] : ""
|
|
color: Theme.textMuted
|
|
font.family: Theme.fontSans
|
|
font.pixelSize: 8
|
|
opacity: 0.7
|
|
}
|
|
}
|
|
|
|
MouseArea {
|
|
id: wsMouse
|
|
anchors.fill: parent
|
|
hoverEnabled: true
|
|
onClicked: GlobalState.switchWorkspace(modelData)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
Separator {}
|
|
|
|
// 5. Spotlight trigger
|
|
Item {
|
|
width: 36
|
|
height: 36
|
|
Layout.alignment: Qt.AlignHCenter
|
|
|
|
Text {
|
|
anchors.centerIn: parent
|
|
text: "⌕"
|
|
font.pixelSize: 20
|
|
color: spotlightMouse.containsMouse ? Theme.accentVolt : Theme.textMuted
|
|
|
|
Behavior on color {
|
|
ColorAnimation { duration: Theme.animFast; easing.type: Easing.OutCubic }
|
|
}
|
|
}
|
|
|
|
MouseArea {
|
|
id: spotlightMouse
|
|
anchors.fill: parent
|
|
hoverEnabled: true
|
|
onClicked: GlobalState.toggleSpotlight()
|
|
}
|
|
}
|
|
|
|
Separator {}
|
|
|
|
// 7. Pinned Apps
|
|
Column {
|
|
Layout.alignment: Qt.AlignHCenter
|
|
spacing: 8
|
|
|
|
DockIcon {
|
|
appClass: ""
|
|
execCmd: "nautilus"
|
|
iconSource: "finder.svg"
|
|
tooltipText: "Finder"
|
|
}
|
|
DockIcon {
|
|
appClass: "brave-browser"
|
|
execCmd: "brave"
|
|
iconSource: "browser.svg"
|
|
tooltipText: "Brave Browser"
|
|
}
|
|
DockIcon {
|
|
appClass: "foot"
|
|
execCmd: "foot"
|
|
iconSource: "terminal.svg"
|
|
tooltipText: "Terminal"
|
|
}
|
|
DockIcon {
|
|
appClass: "nvim"
|
|
execCmd: "foot -e nvim"
|
|
iconSource: "code.svg"
|
|
tooltipText: "Code"
|
|
}
|
|
DockIcon {
|
|
appClass: "pavucontrol"
|
|
execCmd: "pavucontrol"
|
|
iconSource: "preferences.svg"
|
|
tooltipText: "Settings"
|
|
}
|
|
DockIcon {
|
|
appClass: ""
|
|
execCmd: "spotify"
|
|
iconSource: "music.svg"
|
|
tooltipText: "Music"
|
|
}
|
|
}
|
|
|
|
Separator {}
|
|
|
|
// 9. Running Apps (non-pinned)
|
|
Column {
|
|
Layout.alignment: Qt.AlignHCenter
|
|
spacing: 8
|
|
|
|
Repeater {
|
|
model: {
|
|
var pinned = ["foot", "brave-browser", "pavucontrol", "nvim", "nautilus", "spotify", ""]
|
|
var running = []
|
|
var seen = {}
|
|
if (GlobalState.runningApps) {
|
|
for (var i = 0; i < GlobalState.runningApps.length; i++) {
|
|
// hyprctl clients entries are objects; extract the class string
|
|
var cls = GlobalState.runningApps[i] && GlobalState.runningApps[i].class
|
|
if (cls && cls.length > 0 && pinned.indexOf(cls) === -1 && !seen[cls]) {
|
|
seen[cls] = true
|
|
running.push(cls)
|
|
}
|
|
}
|
|
}
|
|
return running
|
|
}
|
|
|
|
delegate: Item {
|
|
width: 36
|
|
height: 36
|
|
|
|
Rectangle {
|
|
anchors.centerIn: parent
|
|
width: 24
|
|
height: 24
|
|
radius: 12
|
|
color: Qt.rgba(1, 1, 1, 0.1)
|
|
|
|
Text {
|
|
anchors.centerIn: parent
|
|
text: modelData && modelData.length > 0 ? modelData.charAt(0).toUpperCase() : "?"
|
|
color: Theme.textPrimary
|
|
font.family: Theme.fontSans
|
|
font.pixelSize: 12
|
|
}
|
|
}
|
|
|
|
Rectangle {
|
|
width: 4
|
|
height: 4
|
|
radius: 2
|
|
color: Theme.accentVolt
|
|
anchors.bottom: parent.bottom
|
|
anchors.horizontalCenter: parent.horizontalCenter
|
|
}
|
|
|
|
MouseArea {
|
|
anchors.fill: parent
|
|
hoverEnabled: true
|
|
onClicked: {
|
|
// Focus app logic here
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// 10. Flexible spacer
|
|
Item { Layout.fillHeight: true }
|
|
|
|
Separator {}
|
|
|
|
// 12. Telemetry mini-readouts
|
|
Column {
|
|
Layout.alignment: Qt.AlignHCenter
|
|
spacing: 2
|
|
|
|
Text {
|
|
anchors.horizontalCenter: parent.horizontalCenter
|
|
text: "CPU" + (GlobalState.cpuPercent !== undefined ? GlobalState.cpuPercent : "0") + "%"
|
|
font.family: Theme.fontMono
|
|
font.pixelSize: 11
|
|
color: (GlobalState.cpuPercent !== undefined && GlobalState.cpuPercent > 80) ? Theme.accentCoral : Theme.textMuted
|
|
Behavior on color { ColorAnimation { duration: Theme.animFast; easing.type: Easing.OutCubic } }
|
|
}
|
|
Text {
|
|
anchors.horizontalCenter: parent.horizontalCenter
|
|
text: "RAM" + (GlobalState.memUsedGb !== undefined ? GlobalState.memUsedGb : "0") + "G"
|
|
font.family: Theme.fontMono
|
|
font.pixelSize: 11
|
|
color: (GlobalState.memPercent !== undefined && GlobalState.memPercent > 85) ? Theme.accentCoral : Theme.textMuted
|
|
Behavior on color { ColorAnimation { duration: Theme.animFast; easing.type: Easing.OutCubic } }
|
|
}
|
|
Text {
|
|
anchors.horizontalCenter: parent.horizontalCenter
|
|
text: "VRM" + (GlobalState.gpuVramUsed !== undefined ? GlobalState.gpuVramUsed : "0") + "G"
|
|
font.family: Theme.fontMono
|
|
font.pixelSize: 11
|
|
color: Theme.textMuted
|
|
}
|
|
}
|
|
|
|
Separator {}
|
|
|
|
// 14. System tray icons
|
|
Column {
|
|
Layout.alignment: Qt.AlignHCenter
|
|
spacing: 8
|
|
|
|
// Volume
|
|
Item {
|
|
width: 36
|
|
height: 36
|
|
Image {
|
|
anchors.centerIn: parent
|
|
width: 16
|
|
height: 16
|
|
source: Qt.resolvedUrl("../assets/volume.svg")
|
|
sourceSize: Qt.size(16, 16)
|
|
opacity: volMouse.containsMouse ? 1.0 : 0.7
|
|
Behavior on opacity { NumberAnimation { duration: Theme.animFast; easing.type: Easing.OutCubic } }
|
|
}
|
|
MouseArea {
|
|
id: volMouse
|
|
anchors.fill: parent
|
|
hoverEnabled: true
|
|
onClicked: {
|
|
GlobalState.systemHudActiveSection = "volume"
|
|
GlobalState.systemHudVisible = true
|
|
}
|
|
}
|
|
}
|
|
|
|
// WiFi
|
|
Item {
|
|
width: 36
|
|
height: 36
|
|
Image {
|
|
anchors.centerIn: parent
|
|
width: 16
|
|
height: 16
|
|
source: Qt.resolvedUrl("../assets/wifi.svg")
|
|
sourceSize: Qt.size(16, 16)
|
|
opacity: GlobalState.wifiConnected ? 0.7 : 0.3
|
|
Behavior on opacity { NumberAnimation { duration: Theme.animFast; easing.type: Easing.OutCubic } }
|
|
}
|
|
MouseArea {
|
|
anchors.fill: parent
|
|
hoverEnabled: true
|
|
onClicked: {
|
|
GlobalState.systemHudActiveSection = "network"
|
|
GlobalState.systemHudVisible = true
|
|
}
|
|
}
|
|
}
|
|
|
|
// Battery
|
|
Item {
|
|
width: 36
|
|
height: 44
|
|
visible: GlobalState.batteryPresent !== undefined ? GlobalState.batteryPresent : false
|
|
|
|
Column {
|
|
anchors.centerIn: parent
|
|
spacing: 2
|
|
|
|
Image {
|
|
anchors.horizontalCenter: parent.horizontalCenter
|
|
width: 16
|
|
height: 16
|
|
source: Qt.resolvedUrl("../assets/battery.svg")
|
|
sourceSize: Qt.size(16, 16)
|
|
opacity: (GlobalState.batteryPercent !== undefined && GlobalState.batteryPercent < 20) ? 1.0 : 0.7
|
|
}
|
|
|
|
Text {
|
|
anchors.horizontalCenter: parent.horizontalCenter
|
|
text: (GlobalState.batteryPercent !== undefined ? GlobalState.batteryPercent : "100") + "%"
|
|
font.family: Theme.fontMono
|
|
font.pixelSize: 9
|
|
color: (GlobalState.batteryPercent !== undefined && GlobalState.batteryPercent < 20) ? Theme.accentCoral : Theme.textSecondary
|
|
}
|
|
}
|
|
|
|
MouseArea {
|
|
anchors.fill: parent
|
|
hoverEnabled: true
|
|
onClicked: {
|
|
GlobalState.systemHudActiveSection = "battery"
|
|
GlobalState.systemHudVisible = true
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
Separator {}
|
|
|
|
// 16. Clock
|
|
Item {
|
|
width: 36
|
|
height: 44
|
|
Layout.alignment: Qt.AlignHCenter
|
|
|
|
Column {
|
|
anchors.centerIn: parent
|
|
spacing: 2
|
|
|
|
Text {
|
|
anchors.horizontalCenter: parent.horizontalCenter
|
|
text: GlobalState.timeString !== undefined ? GlobalState.timeString : "00:00"
|
|
font.family: Theme.fontMono
|
|
font.pixelSize: 12
|
|
color: Theme.textPrimary
|
|
}
|
|
|
|
Text {
|
|
anchors.horizontalCenter: parent.horizontalCenter
|
|
text: GlobalState.dateString !== undefined ? GlobalState.dateString : "Jan 01"
|
|
font.family: Theme.fontMono
|
|
font.pixelSize: 9
|
|
color: Theme.textMuted
|
|
}
|
|
}
|
|
|
|
MouseArea {
|
|
anchors.fill: parent
|
|
hoverEnabled: true
|
|
onClicked: {
|
|
GlobalState.systemHudActiveSection = "calendar"
|
|
GlobalState.systemHudVisible = true
|
|
}
|
|
}
|
|
}
|
|
|
|
// Bottom spacer
|
|
Item { height: 4; Layout.fillWidth: true }
|
|
}
|
|
}
|