import Quickshell import Quickshell.Io import Quickshell.Hyprland import Quickshell.Wayland import Quickshell.Widgets import Quickshell.Services.SystemTray import Quickshell.Services.Pipewire import Quickshell.Services.UPower import QtQuick import QtQuick.Layouts import QtQuick.Controls ShellRoot { id: root // ───────────── SETTINGS & THEMING ───────────── readonly property string mono: "JetBrainsMono Nerd Font" readonly property int barWidth: 42 readonly property int wsCount: 5 readonly property color cBar: "#0a0a0a" readonly property color cPanel: "#0d0d0d" readonly property color cBorder: "#333333" readonly property color cText: "#c8c8c8" readonly property color cDim: "#555555" readonly property color cBright: "#ffffff" readonly property color cAccent: "#ffffff" readonly property color cWarn: "#e05555" // ───────────── STATE ───────────── property bool launcherOpen: false property bool netUp: false property bool btOn: false property string activeApplet: "" PwObjectTracker { objects: [Pipewire] } IpcHandler { target: "launcher" function toggle(): void { root.launcherOpen = !root.launcherOpen } function open(): void { root.launcherOpen = true } function close(): void { root.launcherOpen = false } } SystemClock { id: clock; precision: SystemClock.Minutes } Process { id: statusProc command: ["sh", "-c", "nmcli -t -f STATE general 2>/dev/null | grep -q '^connected' && echo net=1 || echo net=0; " + "nmcli -t -f WIRELESS radio 2>/dev/null | grep -q 'enabled' && echo bt=1 || echo bt=0"] stdout: StdioCollector { onStreamFinished: { root.netUp = text.includes("net=1") root.btOn = text.includes("bt=1") } } } Timer { interval: 5000; running: true; repeat: true; triggeredOnStart: true; onTriggered: statusProc.running = true } // ───────────── VERTICAL BAR ───────────── Variants { model: Quickshell.screens PanelWindow { id: bar required property var modelData screen: modelData anchors { top: true; bottom: true; left: true } implicitWidth: root.barWidth color: root.cBar Rectangle { anchors { top: parent.top; bottom: parent.bottom; right: parent.right } width: 1 color: root.cBorder } // Launcher Button & Workspaces (Top) ColumnLayout { anchors { top: parent.top; topMargin: 12; horizontalCenter: parent.horizontalCenter } spacing: 6 // App Launcher Icon Item { Layout.alignment: Qt.AlignHCenter implicitWidth: 32; implicitHeight: 32 Text { anchors.centerIn: parent text: "" font.family: root.mono; font.pixelSize: 14 color: root.launcherOpen ? root.cBright : root.cDim } MouseArea { anchors.fill: parent onClicked: root.launcherOpen = !root.launcherOpen } } Rectangle { Layout.alignment: Qt.AlignHCenter; width: 16; height: 1; color: root.cBorder; Layout.bottomMargin: 4 } Repeater { model: root.wsCount delegate: Rectangle { required property int index readonly property int wsId: index + 1 readonly property bool active: Hyprland.focusedWorkspace?.id === wsId readonly property bool occupied: Hyprland.workspaces.values.some(w => w.id === wsId) Layout.alignment: Qt.AlignHCenter implicitWidth: 32; implicitHeight: 32 color: "transparent" Text { anchors.centerIn: parent text: parent.wsId font.family: root.mono font.pixelSize: 12 font.bold: parent.active color: parent.active ? root.cBright : (parent.occupied ? root.cText : root.cDim) } MouseArea { anchors.fill: parent onClicked: Quickshell.execDetached(["hyprctl", "dispatch", "workspace " + parent.wsId]) } } } } // Clock & Applet Triggers (Bottom) - NOW WITH BLUETOOTH & NETWORK INDICATORS ColumnLayout { anchors { bottom: parent.bottom; bottomMargin: 12; horizontalCenter: parent.horizontalCenter } spacing: 12 Text { Layout.alignment: Qt.AlignHCenter; text: Qt.formatDateTime(clock.date, "HH"); font.family: root.mono; font.pixelSize: 12; font.bold: true; color: root.cBright } Text { Layout.alignment: Qt.AlignHCenter; text: Qt.formatDateTime(clock.date, "mm"); font.family: root.mono; font.pixelSize: 12; color: root.cDim; Layout.topMargin: -8 } Rectangle { Layout.alignment: Qt.AlignHCenter; width: 16; height: 1; color: root.cBorder; Layout.topMargin: 4; Layout.bottomMargin: 4 } // NETWORK INDICATOR (ADDED) Text { Layout.alignment: Qt.AlignHCenter text: root.netUp ? "" : "" // Wi-Fi when connected, Ethernet when not (or vice versa based on preference) font.family: root.mono; font.pixelSize: 14 color: root.netUp ? root.cAccent : root.cDim MouseArea { anchors.fill: parent; anchors.margins: -8; onClicked: root.activeApplet = root.activeApplet === "wifi" ? "" : "wifi" } } Rectangle { Layout.alignment: Qt.AlignHCenter; width: 16; height: 1; color: root.cBorder; Layout.topMargin: 4; Layout.bottomMargin: 4 } // BLUETOOTH INDICATOR (ADDED) Text { Layout.alignment: Qt.AlignHCenter text: root.btOn ? "" : "" // Bluetooth on/off font.family: root.mono; font.pixelSize: 14 color: root.btOn ? root.cAccent : root.cDim MouseArea { anchors.fill: parent; anchors.margins: -8; onClicked: root.activeApplet = root.activeApplet === "bluetooth" ? "" : "bluetooth" } } Rectangle { Layout.alignment: Qt.AlignHCenter; width: 16; height: 1; color: root.cBorder; Layout.topMargin: 4; Layout.bottomMargin: 4 } Text { Layout.alignment: Qt.AlignHCenter text: Pipewire.defaultAudioSink?.audio?.muted ? "" : "" font.family: root.mono; font.pixelSize: 14 color: root.activeApplet === "sound" ? root.cAccent : root.cText MouseArea { anchors.fill: parent; anchors.margins: -8; onClicked: root.activeApplet = root.activeApplet === "sound" ? "" : "sound" } } } } } // ───────────── APP LAUNCHER OVERLAY ───────────── PanelWindow { id: launcherWindow visible: root.launcherOpen screen: Quickshell.screens.find(s => s.name === Hyprland.focusedMonitor?.name) ?? Quickshell.screens[0] // Centered overlay matching the design in screenshots implicitWidth: 320 implicitHeight: 520 color: "transparent" WlrLayershell.layer: WlrLayer.Overlay WlrLayershell.namespace: "launcher" WlrLayershell.keyboardFocus: WlrKeyboardFocus.Exclusive Rectangle { anchors.fill: parent color: root.cPanel border.color: root.cBorder border.width: 1 FocusScope { id: launcherScope anchors.fill: parent focus: launcherWindow.visible Keys.onEscapePressed: root.launcherOpen = false ColumnLayout { anchors.fill: parent anchors.margins: 12 spacing: 10 // Search Input Box ("Apps...") Rectangle { Layout.fillWidth: true implicitHeight: 34 color: "#141414" border.color: searchInput.activeFocus ? root.cBright : root.cBorder border.width: 1 RowLayout { anchors.fill: parent anchors.leftMargin: 10 anchors.rightMargin: 10 spacing: 8 Text { text: "" font.family: root.mono font.pixelSize: 12 color: root.cDim } TextInput { id: searchInput Layout.fillWidth: true font.family: root.mono font.pixelSize: 12 color: root.cBright focus: true selectByMouse: true Text { text: "Apps..." font.family: root.mono font.pixelSize: 12 color: root.cDim visible: searchInput.text === "" } Keys.onDownPressed: appListView.incrementCurrentIndex() Keys.onUpPressed: appListView.decrementCurrentIndex() Keys.onReturnPressed: { if (appListView.currentItem) { appListView.currentItem.launch() } } } } } // Application List ListView { id: appListView Layout.fillWidth: true Layout.fillHeight: true clip: true spacing: 2 currentIndex: 0 model: appListProc.apps delegate: Rectangle { id: appItem required property var modelData required property int index width: appListView.width height: 36 color: ListView.isCurrentItem ? "#1a1a1a" : (itemArea.containsMouse ? "#141414" : "transparent") border.color: ListView.isCurrentItem ? root.cBorder : "transparent" function launch() { Quickshell.execDetached(["sh", "-c", modelData.exec]) root.launcherOpen = false searchInput.text = "" } RowLayout { anchors.fill: parent anchors.leftMargin: 10 anchors.rightMargin: 10 spacing: 10 Text { text: "" font.family: root.mono font.pixelSize: 13 color: ListView.isCurrentItem ? root.cBright : root.cDim } Text { text: modelData.name font.family: root.mono font.pixelSize: 12 color: ListView.isCurrentItem ? root.cBright : root.cText Layout.fillWidth: true elide: Text.ElideRight } } MouseArea { id: itemArea anchors.fill: parent hoverEnabled: true onClicked: appItem.launch() } } } } } // Process to fetch installed desktop applications Process { id: appListProc property var rawApps: [] property var apps: { const query = searchInput.text.toLowerCase().trim() if (!query) return rawApps return rawApps.filter(a => a.name.toLowerCase().includes(query)) } command: ["python3", "-c", ` import os, glob apps = [] dirs = ['/usr/share/applications', os.path.expanduser('~/.local/share/applications')] for d in dirs: for path in glob.glob(os.path.join(d, '*.desktop')): try: with open(path, 'r', encoding='utf-8', errors='ignore') as f: name, exec_cmd, nodisplay = "", "", False for line in f: if line.startswith('Name=') and not name: name = line.split('=', 1)[1].strip() elif line.startswith('Exec=') and not exec_cmd: exec_cmd = line.split('=', 1)[1].strip().split('%')[0].strip() elif line.startswith('NoDisplay=true'): nodisplay = True if name and exec_cmd and not nodisplay: apps.append(f"{name}|||{exec_cmd}") except: pass apps = sorted(list(set(apps)), key=lambda x: x.lower()) for a in apps: print(a) `] stdout: StdioCollector { onStreamFinished: { const lines = text.trim().split("\n") let parsed = [] for (let line of lines) { const parts = line.split("|||") if (parts.length === 2) { parsed.push({ name: parts[0], exec: parts[1] }) } } appListProc.rawApps = parsed } } } Component.onCompleted: appListProc.running = true onVisibleChanged: { if (visible) { searchInput.text = "" searchInput.forceActiveFocus() } } } // ───────────── APPLETS POPUP WINDOW ───────────── PanelWindow { id: appletWindow visible: root.activeApplet !== "" screen: Quickshell.screens.find(s => s.name === Hyprland.focusedMonitor?.name) ?? Quickshell.screens[0] anchors { left: true; bottom: true } margins.left: root.barWidth + 12 margins.bottom: 12 implicitWidth: 340 implicitHeight: root.activeApplet === "sound" ? 420 : 380 color: "transparent" WlrLayershell.layer: WlrLayer.Overlay WlrLayershell.namespace: "applet" Rectangle { anchors.fill: parent color: root.cPanel border.color: root.cBorder border.width: 1 FocusScope { anchors.fill: parent focus: appletWindow.visible Keys.onEscapePressed: root.activeApplet = "" } // ─ NETWORK APPLET ─ ColumnLayout { anchors.fill: parent; anchors.margins: 16 visible: root.activeApplet === "wifi" spacing: 16 property var wifiList: [] Process { id: wifiScanProc command: ["nmcli", "-t", "-f", "SSID,SIGNAL,SECURITY,IN-USE", "dev", "wifi"] stdout: StdioCollector { onStreamFinished: { const lines = text.trim().split("\n") let results = [] for (let l of lines) { if (!l) continue const parts = l.split(":") if (parts[0] && !results.some(r => r.ssid === parts[0])) { results.push({ ssid: parts[0], signal: parseInt(parts[1]), active: parts[3] === "*" }) } } results.sort((a, b) => b.active - a.active || b.signal - a.signal) parent.wifiList = results } } } onVisibleChanged: if(visible) wifiScanProc.running = true RowLayout { Layout.fillWidth: true ColumnLayout { spacing: 2 Text { text: "Network"; font.family: root.mono; font.pixelSize: 14; font.bold: true; color: root.cBright } Text { text: "WI-FI & ETHERNET"; font.family: root.mono; font.pixelSize: 10; color: root.cDim } } Item { Layout.fillWidth: true } Rectangle { width: 32; height: 18; color: root.netUp ? root.cBright : root.cBorder Rectangle { x: root.netUp ? 15 : 1; y: 1; width: 16; height: 16; color: root.cPanel; Behavior on x { NumberAnimation { duration: 150 } } } } } Rectangle { Layout.fillWidth: true; height: 1; color: root.cBorder } Text { text: "ZNANE SIECI"; font.family: root.mono; font.pixelSize: 10; color: root.cDim } ListView { Layout.fillWidth: true; Layout.fillHeight: true; clip: true; spacing: 8 model: parent.wifiList delegate: Rectangle { width: ListView.view.width; height: 32; color: "transparent" border.color: modelData.active ? root.cBorder : "transparent" RowLayout { anchors.fill: parent; anchors.leftMargin: 12; anchors.rightMargin: 12; spacing: 12 Text { text: ""; font.family: root.mono; font.pixelSize: 12; color: modelData.active ? root.cAccent : root.cDim } Text { text: modelData.ssid; font.family: root.mono; font.pixelSize: 12; color: modelData.active ? root.cBright : root.cText; Layout.fillWidth: true; elide: Text.ElideRight } } MouseArea { anchors.fill: parent; onClicked: { Quickshell.execDetached(["foot", "-e", "nmtui-connect", modelData.ssid]); root.activeApplet = "" } } } } } // ─ AUDIO APPLET ─ ColumnLayout { anchors.fill: parent; anchors.margins: 16 visible: root.activeApplet === "sound" spacing: 12 RowLayout { Layout.fillWidth: true ColumnLayout { spacing: 2 Text { text: "Audio"; font.family: root.mono; font.pixelSize: 14; font.bold: true; color: root.cBright } Text { text: "POKRYJ HAŁAS"; font.family: root.mono; font.pixelSize: 10; color: root.cDim } } Item { Layout.fillWidth: true } Rectangle { width: 32; height: 18; color: !Pipewire.defaultAudioSink?.audio?.muted ? root.cBright : root.cBorder Rectangle { x: !Pipewire.defaultAudioSink?.audio?.muted ? 15 : 1; y: 1; width: 16; height: 16; color: root.cPanel; Behavior on x { NumberAnimation { duration: 150 } } } MouseArea { anchors.fill: parent; onClicked: if(Pipewire.defaultAudioSink?.audio) Pipewire.defaultAudioSink.audio.muted = !Pipewire.defaultAudioSink.audio.muted } } } Rectangle { Layout.fillWidth: true; height: 1; color: root.cBorder; Layout.bottomMargin: 8 } // Input Section Text { text: "INPUT"; font.family: root.mono; font.pixelSize: 10; color: root.cDim } Repeater { model: Pipewire.nodes.values.filter(n => n.mediaClass === "Audio/Source" && !n.description.includes("Monitor")) delegate: ColumnLayout { Layout.fillWidth: true; spacing: 4 RowLayout { Text { text: ""; font.family: root.mono; font.pixelSize: 12; color: root.cDim } Text { text: modelData.description; font.family: root.mono; font.pixelSize: 11; color: root.cText; Layout.fillWidth: true; elide: Text.ElideRight } } Slider { Layout.fillWidth: true; from: 0; to: 1; value: modelData.audio?.volume ?? 0 onValueChanged: if (modelData.audio && Math.abs(modelData.audio.volume - value) > 0.01) modelData.audio.volume = value background: Rectangle { width: parent.width; height: 2; color: root.cBorder; y: parent.height/2; Rectangle { width: parent.visualPosition * parent.width; height: 2; color: root.cBright } } handle: Rectangle { x: parent.visualPosition * (parent.width - width); y: parent.height/2 - height/2; width: 10; height: 10; color: root.cBright } } } } Item { Layout.preferredHeight: 8 } // Output Section Text { text: "OUTPUT"; font.family: root.mono; font.pixelSize: 10; color: root.cDim } Repeater { model: Pipewire.nodes.values.filter(n => n.mediaClass === "Audio/Sink") delegate: ColumnLayout { Layout.fillWidth: true; spacing: 4 RowLayout { Text { text: ""; font.family: root.mono; font.pixelSize: 12; color: root.cDim } Text { text: modelData.description; font.family: root.mono; font.pixelSize: 11; color: root.cText; Layout.fillWidth: true; elide: Text.ElideRight } } Slider { Layout.fillWidth: true; from: 0; to: 1; value: modelData.audio?.volume ?? 0 onValueChanged: if (modelData.audio && Math.abs(modelData.audio.volume - value) > 0.01) modelData.audio.volume = value background: Rectangle { width: parent.width; height: 2; color: root.cBorder; y: parent.height/2; Rectangle { width: parent.visualPosition * parent.width; height: 2; color: root.cBright } } handle: Rectangle { x: parent.visualPosition * (parent.width - width); y: parent.height/2 - height/2; width: 10; height: 10; color: root.cBright } } } } Item { Layout.fillHeight: true } } } } } }