From 489f09377c93f94cd8c3ebb2316d958d4a11f7e3 Mon Sep 17 00:00:00 2001 From: Javier Feliz Date: Sat, 9 Aug 2025 23:07:49 -0400 Subject: [PATCH] Very workable top bar. Start of something cool --- Makefile | 6 ++ default/bars/TopBar.qml | 46 +++++++++++ default/bars/modules/Clock.qml | 18 +++++ default/shell.qml | 29 +++++++ default/widgets/HyprlandWorkspaces.qml | 36 +++++++++ default/widgets/VolumeMixer.qml | 101 +++++++++++++++++++++++++ 6 files changed, 236 insertions(+) create mode 100644 Makefile create mode 100644 default/bars/TopBar.qml create mode 100644 default/bars/modules/Clock.qml create mode 100644 default/shell.qml create mode 100644 default/widgets/HyprlandWorkspaces.qml create mode 100644 default/widgets/VolumeMixer.qml diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..d628a21 --- /dev/null +++ b/Makefile @@ -0,0 +1,6 @@ +dev: + ln -s $(PWD) $(HOME)/.config/quickshell + quickshell -c default + +cleanup: + unlink $(HOME)/.config/quickshell \ No newline at end of file diff --git a/default/bars/TopBar.qml b/default/bars/TopBar.qml new file mode 100644 index 0000000..4ee422e --- /dev/null +++ b/default/bars/TopBar.qml @@ -0,0 +1,46 @@ +import "../widgets" +import "./modules" +import QtQuick +import Quickshell +import Quickshell.Io + +PanelWindow { + property int defaultMargin: 0 + + implicitHeight: 40 + margins.top: defaultMargin + margins.left: defaultMargin + margins.right: defaultMargin + margins.bottom: defaultMargin + aboveWindows: true + + anchors { + top: true + left: true + right: true + } + + Rectangle { + anchors.fill: parent + color: "#000000" + } + + Clock { + anchors.centerIn: parent + } + + // Workspaces + HyprlandWorkspaces { + anchors.verticalCenter: parent.verticalCenter + } + + // Right side - Volume button + VolumeMixer { + anchors { + right: parent.right + verticalCenter: parent.verticalCenter + } + + } + +} diff --git a/default/bars/modules/Clock.qml b/default/bars/modules/Clock.qml new file mode 100644 index 0000000..cdc022a --- /dev/null +++ b/default/bars/modules/Clock.qml @@ -0,0 +1,18 @@ +import QtQuick +import Quickshell +import Quickshell.Io + +Item { + SystemClock { + id: clock + + precision: SystemClock.Seconds + } + + Text { + anchors.centerIn: parent + color: "#ffffff" + text: Qt.formatDateTime(clock.date, "ddd MMM d h:m ap") + } + +} diff --git a/default/shell.qml b/default/shell.qml new file mode 100644 index 0000000..8aa6f54 --- /dev/null +++ b/default/shell.qml @@ -0,0 +1,29 @@ +import "./bars" +import QtQuick +import Quickshell +import Quickshell.Io + +ShellRoot { + // PanelWindow { + // exclusiveZone: 0 + // implicitWidth: 600 + // implicitHeight: 300 + // anchors.top: true + // Rectangle { + // anchors.fill: parent + // color: "black" + // } + // } + + Variants { + model: Quickshell.screens + + delegate: Component { + TopBar { + } + + } + + } + +} diff --git a/default/widgets/HyprlandWorkspaces.qml b/default/widgets/HyprlandWorkspaces.qml new file mode 100644 index 0000000..d540de7 --- /dev/null +++ b/default/widgets/HyprlandWorkspaces.qml @@ -0,0 +1,36 @@ +import QtQuick +import Quickshell +import Quickshell.Hyprland +import Quickshell.Io + +Row { + spacing: 1 + anchors.verticalCenter: parent.verticalCenter + anchors.left: parent.left + anchors.leftMargin: 10 + + Repeater { + model: Hyprland.workspaces + + Rectangle { + visible: modelData.id > 0 // "Magic" workspaces have IDs < 0 + width: 30 + height: 30 + color: modelData.focused ? "#ffffff" : "transparent" + + Text { + anchors.centerIn: parent + text: modelData.id.toString() + color: modelData.focused ? "#000000" : "#ffffff" + } + + MouseArea { + anchors.fill: parent + onClicked: modelData.activate() + } + + } + + } + +} diff --git a/default/widgets/VolumeMixer.qml b/default/widgets/VolumeMixer.qml new file mode 100644 index 0000000..2eaa572 --- /dev/null +++ b/default/widgets/VolumeMixer.qml @@ -0,0 +1,101 @@ +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts +import Quickshell +import Quickshell.Services.Pipewire +import Quickshell.Widgets + +Item { + property bool showPopup: true + // Get the default audio sink + property var audioSink: Pipewire.defaultAudioSink + + implicitWidth: volumeButton.width + 20 + + PwObjectTracker { + objects: [audioSink] + } + + // Volume icon button + Rectangle { + // text height + 10px padding + + id: volumeButton + + color: Pipewire.ready ? "transparent" : "red" + width: volumeText.implicitWidth + 20 + height: volumeText.implicitHeight + 10 + anchors.centerIn: parent + + Text { + id: volumeText + + anchors.centerIn: parent + text: `Vol: ${Math.floor(audioSink.audio.volume * 100)}%` + color: "white" + } + + MouseArea { + anchors.fill: parent + onClicked: { + showPopup = !showPopup; + console.log("Volume clicked, showPopup:", showPopup); + } + } + + } + + // Floating volume popup window + PanelWindow { + id: volumePopup + + visible: showPopup + exclusiveZone: 0 + implicitWidth: 500 + implicitHeight: 100 + anchors.right: parent.right + anchors.top: parent.top + + Rectangle { + anchors.fill: parent + color: "black" + + ColumnLayout { + anchors.fill: parent + anchors.margins: 30 + spacing: 10 + + RowLayout { + Label { + Layout.fillWidth: true + text: `${audioSink.description}` + color: "white" + font.pixelSize: 16 + } + + } + + RowLayout { + spacing: 10 + + Label { + text: `${Math.floor(audioSink.audio.volume * 100)}%` + color: "white" + font.pixelSize: 16 + } + + Slider { + Layout.fillWidth: true + value: audioSink.audio.volume + onValueChanged: audioSink.audio.volume = value + } + + } + + } + + } + + } + +}