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 } } }