From 93c1b00adcf1baff37ec99337691438915797d85 Mon Sep 17 00:00:00 2001 From: Nathan Date: Fri, 6 Mar 2026 08:06:15 -0600 Subject: [PATCH] First commit --- README.md | 9 + config/aurora/default.nix | 30 +++ config/aurora/modules/Bar.qml | 283 +++++++++++++++++++++++ config/aurora/modules/Battery.qml | 95 ++++++++ config/aurora/modules/Bluetooth.qml | 141 +++++++++++ config/aurora/modules/Clock.qml | 29 +++ config/aurora/modules/Dashboard.qml | 0 config/aurora/modules/IdleInhibitor.qml | 34 +++ config/aurora/modules/Launcher.qml | 36 +++ config/aurora/modules/Notif.qml | 71 ++++++ config/aurora/modules/Notifications.qml | 143 ++++++++++++ config/aurora/modules/Power.qml | 120 ++++++++++ config/aurora/modules/Pywal.qml | 58 +++++ config/aurora/modules/SettingsWindow.qml | 0 config/aurora/modules/Tray.qml | 62 +++++ config/aurora/modules/VFlyout.qml | 85 +++++++ config/aurora/modules/Volume.qml | 107 +++++++++ config/aurora/modules/Workspaces.qml | 67 ++++++ config/aurora/shell.qml | 18 ++ config/hybar/default.nix | 28 +++ config/hybar/modules/ActiveWindow.qml | 37 +++ config/hybar/modules/Bar.qml | 175 ++++++++++++++ config/hybar/modules/Battery.qml | 95 ++++++++ config/hybar/modules/Bluetooth.qml | 141 +++++++++++ config/hybar/modules/Clock.qml | 27 +++ config/hybar/modules/Hyprsunset.qml | 30 +++ config/hybar/modules/IdleInhibitor.qml | 34 +++ config/hybar/modules/Launcher.qml | 22 ++ config/hybar/modules/Media.qml | 48 ++++ config/hybar/modules/Notif.qml | 71 ++++++ config/hybar/modules/Notifications.qml | 143 ++++++++++++ config/hybar/modules/Power.qml | 120 ++++++++++ config/hybar/modules/Pywal.qml | 58 +++++ config/hybar/modules/Tray.qml | 62 +++++ config/hybar/modules/Volume.qml | 107 +++++++++ config/hybar/modules/Wifi.qml | 72 ++++++ config/hybar/modules/Workspaces.qml | 47 ++++ config/hybar/shell.qml | 15 ++ dev/shells.nix | 19 ++ dev/systems.nix | 7 + flake.lock | 77 ++++++ flake.nix | 16 ++ 42 files changed, 2839 insertions(+) create mode 100644 README.md create mode 100644 config/aurora/default.nix create mode 100644 config/aurora/modules/Bar.qml create mode 100644 config/aurora/modules/Battery.qml create mode 100644 config/aurora/modules/Bluetooth.qml create mode 100644 config/aurora/modules/Clock.qml create mode 100644 config/aurora/modules/Dashboard.qml create mode 100644 config/aurora/modules/IdleInhibitor.qml create mode 100644 config/aurora/modules/Launcher.qml create mode 100644 config/aurora/modules/Notif.qml create mode 100644 config/aurora/modules/Notifications.qml create mode 100644 config/aurora/modules/Power.qml create mode 100644 config/aurora/modules/Pywal.qml create mode 100644 config/aurora/modules/SettingsWindow.qml create mode 100644 config/aurora/modules/Tray.qml create mode 100644 config/aurora/modules/VFlyout.qml create mode 100644 config/aurora/modules/Volume.qml create mode 100644 config/aurora/modules/Workspaces.qml create mode 100644 config/aurora/shell.qml create mode 100644 config/hybar/default.nix create mode 100644 config/hybar/modules/ActiveWindow.qml create mode 100644 config/hybar/modules/Bar.qml create mode 100644 config/hybar/modules/Battery.qml create mode 100644 config/hybar/modules/Bluetooth.qml create mode 100644 config/hybar/modules/Clock.qml create mode 100644 config/hybar/modules/Hyprsunset.qml create mode 100644 config/hybar/modules/IdleInhibitor.qml create mode 100644 config/hybar/modules/Launcher.qml create mode 100644 config/hybar/modules/Media.qml create mode 100644 config/hybar/modules/Notif.qml create mode 100644 config/hybar/modules/Notifications.qml create mode 100644 config/hybar/modules/Power.qml create mode 100644 config/hybar/modules/Pywal.qml create mode 100644 config/hybar/modules/Tray.qml create mode 100644 config/hybar/modules/Volume.qml create mode 100644 config/hybar/modules/Wifi.qml create mode 100644 config/hybar/modules/Workspaces.qml create mode 100644 config/hybar/shell.qml create mode 100644 dev/shells.nix create mode 100644 dev/systems.nix create mode 100644 flake.lock create mode 100644 flake.nix diff --git a/README.md b/README.md new file mode 100644 index 0000000..ea9a004 --- /dev/null +++ b/README.md @@ -0,0 +1,9 @@ +# 008 - Aurora + +A desktop shell for Hyprland + +## Goal: +>- Look good +>- Feel good +>- Work good + diff --git a/config/aurora/default.nix b/config/aurora/default.nix new file mode 100644 index 0000000..69b0007 --- /dev/null +++ b/config/aurora/default.nix @@ -0,0 +1,30 @@ +{ ... }: { + + + perSystem = { self', pkgs, system, ... }: { + packages = { + aurora = pkgs.writeShellScriptBin "aurora" '' + ${pkgs.quickshell}/bin/quickshell --path ${self'.packages.aurora-dots}/share "''$@" + ''; + + aurora-dots = pkgs.stdenv.mkDerivation { + + name = "aurora-dots"; + + src = ./.; + + buildInputs = []; + + buildPhase = '' + ''; + + installPhase = '' + mkdir -p $out/share + cp -r $src/* $out/share + ''; + }; + + default = self'.packages.aurora; + }; + }; +} diff --git a/config/aurora/modules/Bar.qml b/config/aurora/modules/Bar.qml new file mode 100644 index 0000000..c98fb1c --- /dev/null +++ b/config/aurora/modules/Bar.qml @@ -0,0 +1,283 @@ +import Quickshell // for PanelWindow +import QtQuick // for Text +import QtQuick.Shapes +import QtQuick.Controls +import QtQuick.Layouts +import Quickshell.Io +import Quickshell.Widgets +import Quickshell.Wayland +import Quickshell.Hyprland + +PanelWindow { + + property real radius: 20 + + onClosed: { + Hyprland.dispatch("exec hyprctl keyword monitor eDP-1,addreserved,0,100,0,0") + } + + anchors { + top: true + left: true + right: true + bottom: true + } + + + Component.onCompleted: { + + //Hyprland.dispatch("exec hyprctl keyword monitor eDP-1,addreserved," + topRect.height + "," + botRect.height + "," + leftRect.width + "," + rightRect.width) + Hyprland.dispatch("exec hyprctl keyword monitor eDP-1,addreserved," + topEx + "," + botEx + "," + leftEx + "," + rightEx) + + } + + property int topEx: topRect.height + property int botEx: botRect.height + + property int leftEx: leftRect.width + property int rightEx: rightRect.width + + + id: root + + exclusionMode: ExclusionMode.Ignore + WlrLayershell.layer: WlrLayer.Top + + //color: Pywal.special.background + color: "transparent" + + mask: Region { + + Region { + item: topRect + } + + Region { + item: leftRect + } + + Region { + item: midFO.visible ? midFO : topRect + //item: midFO + } + } + + WrapperMouseArea { + id: topRectArea + Rectangle { + id: topRect + color: Pywal.special.background + anchors.fill: parent + } + implicitHeight: 10 + implicitWidth: parent.width + + hoverEnabled: true + onEntered: { + midFO.set = !midFO.set + midFO.visible = Qt.binding(() => midFO.set) + } + //onEntered: midFO.visible = true + } + + Rectangle { + id: botRect + y: parent.height - height + color: Pywal.special.background + implicitHeight: 10 + implicitWidth: parent.width + } + + + + Rectangle { + + id: leftRect + + implicitHeight: parent.height + + + implicitWidth: 40 + + color: Pywal.special.background + + + Launcher { + id: launcher + x: parent.width / 2 - implicitWidth / 2 + y: implicitWidth / 3 + Layout.alignment: Qt.AlignHCenter | Qt.AlignTop + } + + Workspaces { + id: workspaces + x: parent.width / 2 - implicitWidth / 2 + y: 20 + launcher.y + launcher.height + Layout.alignment: Qt.AlignHCenter | Qt.AlignTop + } + + IdleInhibitor { + id: idleInhibitor + x: parent.width / 2 - implicitWidth / 2 + y: 20 + workspaces.y + workspaces.height + Layout.alignment: Qt.AlignHCenter | Qt.AlignTop + visible: false + } + } + + Rectangle { + id: rightRect + x: parent.width - width + color: Pywal.special.background + implicitWidth: 10 + implicitHeight: parent.height + } + + Shape { + + x: leftRect.x + leftRect.width - 1 + y: topRect.y + topRect.height - 1 + + ShapePath { + strokeWidth: 4 + strokeColor: Pywal.special.background + fillColor: Pywal.special.background + startX: 0; startY: 0 + + onFillColorChanged: { + console.log(Pywal.special.background) + fillColor = Qt.binding(() => Pywal.special.background) + strokeColor = Qt.binding(() => Pywal.special.background) + } + + PathLine { relativeX: 0; relativeY: radius } + PathArc { + radiusX: radius + radiusY: -radius + relativeX: radius + relativeY: -radius + } + PathLine { relativeX: -radius; relativeY: 0 } + } + } + Shape { + + x: rightRect.x + 1 + y: topRect.y + topRect.height - 1 + + ShapePath { + strokeWidth: 4 + strokeColor: Pywal.special.background + fillColor: Pywal.special.background + startX: 0; startY: 0 + + PathLine { relativeX: 0; relativeY: radius } + PathArc { + direction: PathArc.Counterclockwise + radiusX: radius + radiusY: radius + relativeX: -radius + relativeY: -radius + } + PathLine { relativeX: radius; relativeY: 0 } + } + } + Shape { + + x: leftRect.x + leftRect.width - 1 + y: botRect.y + 1 + + ShapePath { + strokeWidth: 4 + strokeColor: Pywal.special.background + fillColor: Pywal.special.background + startX: 0; startY: 0 + + PathLine { relativeX: 0; relativeY: -radius } + PathArc { + direction: PathArc.Counterclockwise + radiusX: radius + radiusY: radius + relativeX: radius + relativeY: radius + } + PathLine { relativeX: -radius; relativeY: 0 } + } + } + Shape { + + x: rightRect.x + 1 + y: botRect.y + 1 + + ShapePath { + strokeWidth: 4 + strokeColor: Pywal.special.background + fillColor: Pywal.special.background + startX: 0; startY: 0 + + PathLine { relativeX: 0; relativeY: -radius } + PathArc { + radiusX: radius + radiusY: -radius + relativeX: -radius + relativeY: radius + } + PathLine { relativeX: radius; relativeY: 0 } + } + } + + VFlyout { + id: midFO + x: root.screen.width / 2 - width / 2 + y: topRect.y + topRect.height - 1 + + color: Pywal.special.background + + visible: set + + property bool set: true + + item: mid + + RowLayout { + id: mid + + Notifications { + id: notifications + window: root + } + + Battery { + window: root + popupOffset: x + midFO.x + } + + Tray { + window: root + popupOffset: x + midFO.x + } + + Clock { + id: clock + } + + Bluetooth { + window: root + popupOffset: x + midFO.x + } + + Volume { + window: root + popupOffset: x + midFO.x + } + + Power { + id: power + window: root + popupOffset: x + midFO.x + } + } + + radius: radius + } +} diff --git a/config/aurora/modules/Battery.qml b/config/aurora/modules/Battery.qml new file mode 100644 index 0000000..1fffa9c --- /dev/null +++ b/config/aurora/modules/Battery.qml @@ -0,0 +1,95 @@ +import Quickshell // for PanelWindow +import QtQuick // for Text +import QtQuick.Controls +import QtQuick.Layouts +import Quickshell.Io +import Quickshell.Widgets +import Quickshell.Hyprland +import Quickshell.Services.UPower + +ClippingWrapperRectangle { + radius: 5 + width: 100; height: 30 + color: "red" + Button { + id: button + text: if(UPower.onBattery) { + "󰁹 " + Math.floor(UPower.displayDevice.percentage * 100) + "%" + } else { + "󰂄 " + Math.floor(UPower.displayDevice.percentage * 100) + "%" + } + font.pointSize: 12 + implicitHeight: parent.height + //icon.color: "red" + //icon.source: "/nix/store/c4dcn4vl0v5njv4d587sazrad1xgyd9h-rose-pine-icon-theme-unstable-2022-09-01/share/icons/rose-pine/symbolic/devices/battery-symbolic.svg" + onClicked: { + menu.visible = true + grab.active = true + } + } + + required property var window + required property real popupOffset + id: root + + PopupWindow { + + id: menu + + anchor.window: window + anchor.rect.x: popupOffset + anchor.rect.y: 50 + implicitWidth: 250 + implicitHeight: 150 + visible: false + + color: "transparent" + + ClippingWrapperRectangle { + radius: 5 + + implicitHeight: parent.height - 20 + implicitWidth: parent.width + + ColumnLayout { + + spacing: 0 + + Button { + Layout.topMargin: 5 + x: (parent.width - width) / 2 + implicitWidth: parent.width - 10 + implicitHeight: parent.height / 5 - parent.spacing + + text: 'performance' + onClicked: PowerProfiles.profile = PowerProfile.Performance + visible: PowerProfiles.hasPerformanceProfile + } + Button { + Layout.topMargin: 5 + x: (parent.width - width) / 2 + implicitWidth: parent.width - 10 + implicitHeight: parent.height / 5 - parent.spacing + + text: 'balanced' + onClicked: PowerProfiles.profile = PowerProfile.Balanced + } + Button { + Layout.topMargin: 5 + x: (parent.width - width) / 2 + implicitWidth: parent.width - 10 + implicitHeight: parent.height / 5 - parent.spacing + + text: 'power saver' + onClicked: PowerProfiles.profile = PowerProfile.PowerSaver + } + } + } + + HyprlandFocusGrab { + id: grab + windows: [ menu ] + onCleared: menu.visible = false + } + } +} diff --git a/config/aurora/modules/Bluetooth.qml b/config/aurora/modules/Bluetooth.qml new file mode 100644 index 0000000..e59d15f --- /dev/null +++ b/config/aurora/modules/Bluetooth.qml @@ -0,0 +1,141 @@ +import Quickshell // for PanelWindow +import QtQuick // for Text +import QtQuick.Controls +import QtQuick.Layouts +import Quickshell.Io +import Quickshell.Widgets +import Quickshell.Hyprland +import Quickshell.Bluetooth + +ClippingWrapperRectangle { + + + radius: 5 + implicitWidth: 30; implicitHeight: 30 + Button { + id: button + text: "" + font.pointSize: 16 + + onClicked: { + menu.visible = true + grab.active = true + } + implicitHeight: parent.height + } + + required property PanelWindow window + required property real popupOffset + id: root + + PopupWindow { + + id: menu + + anchor.window: window + anchor.rect.x: popupOffset - width + anchor.rect.y: 50 + implicitWidth: 250 + implicitHeight: 150 + visible: false + + color: "transparent" + + ClippingWrapperRectangle { + radius: 5 + + implicitHeight: parent.height - 20 + implicitWidth: parent.width + + ColumnLayout { + + spacing: 0 + + ClippingWrapperRectangle { + radius: 5 + implicitWidth: parent.width - 2 * Layout.margins + implicitHeight: 30 + Layout.alignment: Qt.AlignHCenter | Qt.AlignTop + Layout.margins: 5 + color: "#ff3333aa" + + RowLayout { + Text { + text: 'Bluetooth' + Layout.alignment: Qt.AlignLeft | Qt.AlignVCenter + Layout.margins: 5 + } + + Switch { + Layout.alignment: Qt.AlignRight | Qt.AlignVCenter + //Layout.margins: 5 + checked: Bluetooth.defaultAdapter.enabled + onClicked: Bluetooth.defaultAdapter.enabled = checked + } + } + + } + + ScrollView { + Layout.alignment: Qt.AlignHCenter | Qt.AlignTop + Layout.margins: 5 + + implicitWidth: parent.width - 4 * Layout.margins + implicitHeight: menu.height / 2 + + id: scroll + + ColumnLayout { + spacing: 0 + + Repeater { + + id: rep + + model: Bluetooth.devices.values + + ClippingWrapperRectangle { + radius: 5 + color: "#ff3333aa" + + implicitWidth: menu.width - 3 * scroll.x + implicitHeight: 40 + + Layout.alignment: Qt.AlignHCenter | Qt.AlignTop + Layout.margins: 5 + + RowLayout { + Text { + Layout.alignment: Qt.AlignLeft | Qt.AlignVCenter + Layout.margins: 5 + + text: rep.model[index].name + } + + Button { + Layout.alignment: Qt.AlignRight | Qt.AlignVCenter + Layout.rightMargin: 5 + text: 'Connect' + + onClicked: rep.model[index].connected = !rep.model[index].connected + } + } + + + } + + } + } + + } + + } + } + + HyprlandFocusGrab { + id: grab + windows: [ menu ] + onCleared: menu.visible = false + } + } +} diff --git a/config/aurora/modules/Clock.qml b/config/aurora/modules/Clock.qml new file mode 100644 index 0000000..56c67a4 --- /dev/null +++ b/config/aurora/modules/Clock.qml @@ -0,0 +1,29 @@ +import QtQuick // for Text +import QtQuick.Controls +import QtQuick.Layouts +import Quickshell.Widgets +import Quickshell + +WrapperMouseArea { + implicitWidth: t.contentWidth + 10 + implicitHeight: 30 + + ClippingWrapperRectangle { + id: rect + color: Pywal.colors.color12 + radius: 5 + anchors.fill: parent + Text { + id: t + verticalAlignment: Text.AlignVCenter + horizontalAlignment: Text.AlignHCenter + text: Qt.formatDateTime(clock.date, "dddd HH:mm:ss MM/dd/yyyy") + font.pointSize: 11 + + SystemClock { + id: clock + precision: SystemClock.Seconds + } + } + } +} diff --git a/config/aurora/modules/Dashboard.qml b/config/aurora/modules/Dashboard.qml new file mode 100644 index 0000000..e69de29 diff --git a/config/aurora/modules/IdleInhibitor.qml b/config/aurora/modules/IdleInhibitor.qml new file mode 100644 index 0000000..26e233e --- /dev/null +++ b/config/aurora/modules/IdleInhibitor.qml @@ -0,0 +1,34 @@ +import Quickshell // for PanelWindow +import QtQuick // for Text +import QtQuick.Controls +import Quickshell.Io +import Quickshell.Widgets + +ClippingWrapperRectangle { + + property real interval: 100 + id: root + + radius: 5 + implicitWidth: 30; height: 30 + Button { + id: button + text: "󰒳 " + font.pointSize: 16 + Process { + id: idlent + running: true + command: ["systemd-inhibit", "--what=idle", "sleep", root.interval.toString()] + + onExited: { + running = button.text == "󰒲 " ? false : true + } + } + + onClicked: { + idlent.running = button.text == "󰒲 " ? true : false + button.text = button.text == "󰒲 " ? "󰒳 " : "󰒲 " + } + implicitHeight: parent.height + } +} diff --git a/config/aurora/modules/Launcher.qml b/config/aurora/modules/Launcher.qml new file mode 100644 index 0000000..835322f --- /dev/null +++ b/config/aurora/modules/Launcher.qml @@ -0,0 +1,36 @@ +import Quickshell // for PanelWindow +import QtQuick // for Text +import QtQuick.Controls +import Quickshell.Io +import Quickshell.Widgets + +WrapperMouseArea { + ClippingWrapperRectangle { + radius: 5 + implicitWidth: 30; implicitHeight: 30 + Text { + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + anchors.fill: parent + text: " " + font.pointSize: 16 + + color: Pywal.special.foreground + } + color: { + containsMouse + ? Pywal.colors.color12 + : Pywal.colors.color1 + } + } + + hoverEnabled: true + + Process { + id: launcher + running: false + command: ["rofi", "-show", "drun"] + } + + onClicked: launcher.running = true +} diff --git a/config/aurora/modules/Notif.qml b/config/aurora/modules/Notif.qml new file mode 100644 index 0000000..5020629 --- /dev/null +++ b/config/aurora/modules/Notif.qml @@ -0,0 +1,71 @@ +import Quickshell +import QtQuick // for Text +import QtQuick.Controls +import QtQuick.Layouts +import Quickshell.Services.Notifications +import Quickshell.Io +import Quickshell.Widgets +import Quickshell.Hyprland + +ClippingWrapperRectangle { + id: notif + Layout.alignment: Qt.AlignHCenter | Qt.AlignTop + Layout.margins: 5 + radius: 10 + implicitWidth: parent.width - 2 * Layout.margins + implicitHeight: 100 + + color: Pywal.colors.color2 + + required property Notification src + + MouseArea { + anchors.fill: parent + + RowLayout { + Image { + //anchors.fill: parent + source: { + console.log(notif.src) + let icon = notif.src.image + if (icon.includes("?path=")) { + const [name, path] = icon.split("?path="); + icon = Qt.resolvedUrl(`${path}/${name.slice(name.lastIndexOf("/") + 1)}`); + } + return icon + } + + Layout.maximumWidth: 100 + Layout.maximumHeight: 100 + } + + ColumnLayout { + Layout.topMargin: 10 + Layout.alignment: Qt.AlignLeft | Qt.AlignTop + Text { + color: Pywal.special.background + Layout.alignment: Qt.AlignLeft | Qt.AlignTop + text: notif.src.summary + Layout.leftMargin: 10 + font.pointSize: 14 + } + Text { + color: Pywal.special.background + Layout.alignment: Qt.AlignLeft | Qt.AlignVCenter + text: notif.src.body + Layout.leftMargin: 10 + font.pointSize: 12 + } + } + } + + acceptedButtons: Qt.LeftButton | Qt.RightButton + + onClicked: mouse => { + if(mouse.button == Qt.LeftButton) { + notif.src.dismiss() + } else if(mouse.button == Qt.RightButton) { + } + } + } +} diff --git a/config/aurora/modules/Notifications.qml b/config/aurora/modules/Notifications.qml new file mode 100644 index 0000000..27dbb0a --- /dev/null +++ b/config/aurora/modules/Notifications.qml @@ -0,0 +1,143 @@ +import Quickshell +import QtQuick // for Text +import QtQuick.Controls +import QtQuick.Layouts +import Quickshell.Services.Notifications +import Quickshell.Io +import Quickshell.Widgets +import Quickshell.Hyprland + +Item { + width: 50 + height: 30 + + ClippingWrapperRectangle { + id: barbutton + radius: 5 + anchors.fill: parent + Button { + id: button + text: "󰂚" + font.pointSize: 16 + + onClicked: { + + + menu.visible = true + grab.active = true + } + implicitHeight: parent.height + } + } + + NotificationServer { + id: server + persistenceSupported: true + imageSupported: true + actionsSupported: true + bodyImagesSupported: true + bodySupported: true + bodyHyperlinksSupported: true + inlineReplySupported: true + actionIconsSupported: true + + onNotification: (n) => { + n.tracked = !n.transient + } + + + } + + required property PanelWindow window + id: root + + PopupWindow { + + id: menu + + anchor.window: window + anchor.rect.x: window.width - width + anchor.rect.y: 50 + implicitWidth: 400 + implicitHeight: 1080 - anchor.rect.y + visible: false + + color: "transparent" + + ClippingWrapperRectangle { + radius: 5 + + color: Pywal.special.background + + implicitHeight: parent.height - 20 + implicitWidth: parent.width + + ColumnLayout { + id: lay + + spacing: 10 + + ClippingWrapperRectangle { + color: Pywal.colors.color2 + radius: 5 + Layout.margins: 5 + Layout.alignment: Qt.AlignVCenter | Qt.AlignTop + implicitWidth: menu.width - 2 * Layout.margins + + RowLayout { + width: parent.width + Text { + color: Pywal.colors.color0 + Layout.margins: 5 + Layout.alignment: Qt.AlignLeft | Qt.AlignVCenter + text: 'Notifications' + } + Button { + Layout.alignment: Qt.AlignRight | Qt.AlignVCenter + Layout.margins: 5 + implicitWidth: 20 + implicitHeight: 20 + + text: 'x' + + onClicked: { + while(server.trackedNotifications.values.length > 0) { + server.trackedNotifications.values[0].dismiss() + } + } + } + } + } + + ColumnLayout { + Layout.alignment: Qt.AlignVCenter | Qt.AlignTop + Repeater { + id: rep + + model: server.trackedNotifications.values + + Notif { + required property int index + src: rep.model[index] + } + + onItemAdded: (idx, it) => { + button.text = '󱅫 ' + rep.count + } + + onItemRemoved: (idx, it) => { + button.text = (rep.count - 1) <= 0 ? "󰂚" : '󱅫 ' + (rep.count - 1) + } + } + } + + } + } + + HyprlandFocusGrab { + id: grab + windows: [ menu ] + onCleared: menu.visible = false + } + } +} diff --git a/config/aurora/modules/Power.qml b/config/aurora/modules/Power.qml new file mode 100644 index 0000000..51b7775 --- /dev/null +++ b/config/aurora/modules/Power.qml @@ -0,0 +1,120 @@ +import Quickshell +import QtQuick // for Text +import QtQuick.Controls +import QtQuick.Layouts +import Quickshell.Hyprland +import Quickshell.Io +import Quickshell.Widgets + +Item { + width: 30 + height: 30 + + id: root + + required property PanelWindow window + required property real popupOffset + + ClippingWrapperRectangle { + radius: 5 + width: 30; height: 30 + Button { + id: button + text: " " + font.pointSize: 16 + + onClicked: { + menu.visible = true + grab.active = true + } + implicitHeight: parent.height + } + } + + PopupWindow { + + id: menu + + anchor.window: window + anchor.rect.x: popupOffset + anchor.rect.y: 50 + implicitWidth: 150 + implicitHeight: 250 + visible: false + + color: "transparent" + + ClippingWrapperRectangle { + radius: 5 + + implicitHeight: parent.height - 20 + implicitWidth: parent.width + + ColumnLayout { + + spacing: 0 + + Button { + Layout.topMargin: 5 + x: (parent.width - width) / 2 + implicitWidth: parent.width - 10 + implicitHeight: parent.height / 5 - parent.spacing + + text: 'shutdown' + onClicked: shutdown.running = true + Process { + id: shutdown + running: false + command: ["systemctl", "poweroff"] + } + } + + Button { + x: (parent.width - width) / 2 + implicitWidth: parent.width - 10 + implicitHeight: parent.height / 5 - parent.spacing + text: 'reboot' + onClicked: reboot.running = true + Process { + id: reboot + running: false + command: ["systemctl", "reboot"] + } + } + + Button { + x: (parent.width - width) / 2 + implicitWidth: parent.width - 10 + implicitHeight: parent.height / 5 - parent.spacing + text: 'logout' + onClicked: logout.running = true + Process { + id: logout + running: false + command: ["loginctl", "kill-session", "self" ] + } + } + + Button { + Layout.bottomMargin: 10 + x: (parent.width - width) / 2 + implicitWidth: parent.width - 10 + implicitHeight: parent.height / 5 - parent.spacing + text: 'sleep' + onClicked: sleep.running = true + Process { + id: sleep + running: false + command: ["systemctl", "sleep"] + } + } + } + } + + HyprlandFocusGrab { + id: grab + windows: [ menu ] + onCleared: menu.visible = false + } + } +} diff --git a/config/aurora/modules/Pywal.qml b/config/aurora/modules/Pywal.qml new file mode 100644 index 0000000..957ef03 --- /dev/null +++ b/config/aurora/modules/Pywal.qml @@ -0,0 +1,58 @@ +pragma Singleton + +import Quickshell +import Quickshell.Io + +Singleton { + + property string wallpaper: json.wallpaper + + property string alpha: json.alpha + + property JsonObject special: json.special + property JsonObject colors: json.colors + + FileView { + + path: "/home/nathan/.cache/wal/colors.json" + + watchChanges: true + + onFileChanged: reload() + + JsonAdapter { + id: json + property string wallpaper: "/home/nathan/Pictures/Wallpaper/bluescape.jpg" + + property string alpha: "100" + + property JsonObject special: JsonObject { + property string background: "white" + property string foreground: "white" + property string cursor: "white" + } + + property JsonObject colors: JsonObject { + property string color0: "white" + property string color1: "white" + property string color2: "white" + property string color3: "white" + + property string color4: "white" + property string color5: "white" + property string color6: "white" + property string color7: "white" + + property string color8: "white" + property string color9: "white" + property string color10: "white" + property string color11: "white" + + property string color12: "white" + property string color13: "white" + property string color14: "white" + property string color15: "white" + } + } + } +} diff --git a/config/aurora/modules/SettingsWindow.qml b/config/aurora/modules/SettingsWindow.qml new file mode 100644 index 0000000..e69de29 diff --git a/config/aurora/modules/Tray.qml b/config/aurora/modules/Tray.qml new file mode 100644 index 0000000..f4c7e47 --- /dev/null +++ b/config/aurora/modules/Tray.qml @@ -0,0 +1,62 @@ +import QtQuick // for Text +import QtQuick.Controls +import QtQuick.Layouts +import Quickshell.Services.SystemTray +import Quickshell.Widgets + +Item { + implicitWidth: 10 + rep.count * (2 * lay.spacing + 20) + height: 30 + visible: SystemTray.items.values.length != 0 + + id: root + required property var window + required property real popupOffset + + ClippingWrapperRectangle { + radius: 5 + anchors.fill: parent + RowLayout { + id: lay + spacing: 4 + Repeater { + id: rep + + model: SystemTray.items + ClippingWrapperRectangle { + Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter + radius: 10 + implicitWidth: 20 + implicitHeight: 20 + MouseArea { + anchors.fill: parent + + Image { + anchors.fill: parent + source: { + let icon = SystemTray.items.values[index].icon + if (icon.includes("?path=")) { + const [name, path] = icon.split("?path="); + icon = Qt.resolvedUrl(`${path}/${name.slice(name.lastIndexOf("/") + 1)}`); + } + return icon + } + } + + acceptedButtons: Qt.LeftButton | Qt.RightButton + + onClicked: (mouse) => { + if(mouse.button == Qt.LeftButton) { + SystemTray.items.values[index].activate() + } else if(mouse.button == Qt.RightButton) { + SystemTray.items.values[index].display(root.window, popupOffset, 40) + } + } + } + } + } + } + + + } +} diff --git a/config/aurora/modules/VFlyout.qml b/config/aurora/modules/VFlyout.qml new file mode 100644 index 0000000..ea9f0dd --- /dev/null +++ b/config/aurora/modules/VFlyout.qml @@ -0,0 +1,85 @@ +import QtQuick +import QtQuick.Shapes + +import Quickshell +import Quickshell.Widgets + +MouseArea { + id: root + + property real radius: 15 + property real pad: 10 + property color color + + property Item item + + hoverEnabled: true + + Component.onCompleted: { + + item.y = pad + } + + width: shape.width + height: shape.height + + Shape { + id: shape + + //anchors.centerIn: parent + ShapePath { + id: path + + strokeWidth: 4 + strokeColor: root.color + fillColor: root.color + + startX: -radius - pad; startY: 0 + + PathArc { + radiusX: radius + radiusY: radius + + relativeX: radius + relativeY: radius + } + + PathLine { relativeX: 0; relativeY: 2 * pad + item.height - 2 * radius } + + PathArc { + radiusX: radius + radiusY: radius + + direction: PathArc.Counterclockwise + + relativeX: radius + relativeY: radius + } + + PathLine { x: item.width + pad - radius; relativeY: 0 } + + PathArc { + radiusX: radius + radiusY: radius + + direction: PathArc.Counterclockwise + + relativeX: radius + relativeY: -radius + } + + PathLine { relativeX: 0; relativeY: -item.height + 2 * radius - 2 * pad } + + PathArc { + radiusX: radius + radiusY: radius + + relativeX: radius + relativeY: -radius + } + + PathLine { x: -radius - pad; y: 0 } + } + } +} + diff --git a/config/aurora/modules/Volume.qml b/config/aurora/modules/Volume.qml new file mode 100644 index 0000000..b43778c --- /dev/null +++ b/config/aurora/modules/Volume.qml @@ -0,0 +1,107 @@ +import Quickshell // for PanelWindow +import QtQuick // for Text +import QtQuick.Controls +import QtQuick.Layouts +import Quickshell.Io +import Quickshell.Widgets +import Quickshell.Hyprland +import Quickshell.Services.Pipewire + +ClippingWrapperRectangle { + radius: 5 + width: 100; height: 30 + Button { + id: button + text: (Pipewire.defaultAudioSink?.audio?.muted ? " " : " ") + Math.floor(Pipewire.defaultAudioSink?.audio?.volume * 100) + "%" + font.pointSize: 12 + implicitHeight: parent.height + + PwObjectTracker { + objects: [ Pipewire.defaultAudioSink ] + } + + onClicked: { + menu.visible = true + grab.active = true + } + + } + + required property var window + required property real popupOffset + id: root + + PopupWindow { + + id: menu + + anchor.window: window + anchor.rect.x: popupOffset + anchor.rect.y: 50 + implicitWidth: 250 + implicitHeight: 150 + visible: false + + color: "transparent" + + ClippingWrapperRectangle { + radius: 5 + + implicitHeight: parent.height - 20 + implicitWidth: parent.width + + ScrollView { + ColumnLayout { + + spacing: 0 + + Text { + text: 'Output Devices' + } + + ColumnLayout { + Repeater { + id: outputs + + model: { + Pipewire.nodes.values.filter(n => n.isSink && n.audio && n.nickname != "") + } + + Button { + text: outputs.model[index].nickname + onClicked: Pipewire.preferredDefaultAudioSink = outputs.model[index] + } + } + } + + Text { + text: 'Input Devices' + } + + ColumnLayout { + Repeater { + id: inputs + + model: { + Pipewire.nodes.values.filter(n => !n.isSink && n.audio && n.nickname != "") + } + + Button { + text: inputs.model[index].nickname + onClicked: Pipewire.preferredDefaultAudioSource = inputs.model[index] + } + } + } + + } + } + + } + + HyprlandFocusGrab { + id: grab + windows: [ menu ] + onCleared: menu.visible = false + } + } +} diff --git a/config/aurora/modules/Workspaces.qml b/config/aurora/modules/Workspaces.qml new file mode 100644 index 0000000..d3da5e4 --- /dev/null +++ b/config/aurora/modules/Workspaces.qml @@ -0,0 +1,67 @@ +import QtQuick // for Text +import QtQuick.Controls +import QtQuick.Layouts +import Quickshell.Hyprland +import Quickshell.Widgets + +Item { + implicitHeight: 10 + rep.count * (2 * lay.spacing + 25) + implicitWidth: 30 + + Component.onCompleted: Hyprland.refreshWorkspaces() + + ClippingWrapperRectangle { + color: Pywal.colors.color1 + radius: 3 + anchors.fill: parent + ColumnLayout { + id: lay + Repeater { + id: rep + + property var ws: { + let arr = []; + Hyprland.workspaces.values.forEach((w) => { if(w.id > 0) arr.push(w) }) + return arr; + } + + model: ws + WrapperMouseArea { + Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter + ClippingWrapperRectangle { + id: rect + radius: 3 + implicitWidth: 24 + implicitHeight: 24 + color: { + Hyprland.focusedWorkspace.id == rep.model[index].id + ? Pywal.colors.color13 + : containsMouse + ? Pywal.colors.color12 + : Pywal.colors.color4 + } + + Text { + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + + text: rep.model[index].id + + color: { + Hyprland.focusedWorkspace.id == rep.model[index].id + ? Pywal.colors.color1 + : Pywal.special.foreground + } + } + } + hoverEnabled: true + onClicked: { + rep.model[index].activate() + } + } + } + } + + + } +} diff --git a/config/aurora/shell.qml b/config/aurora/shell.qml new file mode 100644 index 0000000..749e7b3 --- /dev/null +++ b/config/aurora/shell.qml @@ -0,0 +1,18 @@ +//@ pragma Env QS_NO_RELOAD_POPUP=1 +//@ pragma Env QSG_RENDER_LOOP=threaded +//@ pragma Env QT_QUICK_FLICKABLE_WHEEL_DECELERATION=10000 + +//@ pragma UseQApplication + +import QtQuick +import Quickshell // for ShellRoot +import Quickshell.Hyprland +import qs.modules + +ShellRoot { + + Bar { + id: bar + } + +} diff --git a/config/hybar/default.nix b/config/hybar/default.nix new file mode 100644 index 0000000..71ed371 --- /dev/null +++ b/config/hybar/default.nix @@ -0,0 +1,28 @@ +{ ... }: { + + + perSystem = { self', pkgs, system, ... }: { + packages = { + hybar = pkgs.writeShellScriptBin "hybar" '' + ${pkgs.quickshell}/bin/quickshell --path ${self'.packages.hybar-dots}/share "''$@" + ''; + + hybar-dots = pkgs.stdenv.mkDerivation { + + name = "hybar-dots"; + + src = ./.; + + buildInputs = []; + + buildPhase = '' + ''; + + installPhase = '' + mkdir -p $out/share + cp -r $src/* $out/share + ''; + }; + }; + }; +} diff --git a/config/hybar/modules/ActiveWindow.qml b/config/hybar/modules/ActiveWindow.qml new file mode 100644 index 0000000..099cbce --- /dev/null +++ b/config/hybar/modules/ActiveWindow.qml @@ -0,0 +1,37 @@ +import QtQuick // for Text +import QtQuick.Controls +import QtQuick.Layouts +import Quickshell.Widgets +import Quickshell.Hyprland +import Quickshell + +Item { + implicitWidth: t.contentWidth + 10 + implicitHeight: 30 + + ClippingWrapperRectangle { + radius: 5 + anchors.fill: parent + Text { + id: t + verticalAlignment: Text.AlignVCenter + horizontalAlignment: Text.AlignHCenter + text: { + if(hws.toplevels.values.length > 0) { + return Hyprland.activeToplevel.title + } else { + return " Desktop" + } + } + + property HyprlandWorkspace hws: Hyprland.focusedWorkspace + + onHwsChanged: { + Hyprland.refreshToplevels() + Hyprland.refreshWorkspaces() + } + + font.pointSize: 11 + } + } +} diff --git a/config/hybar/modules/Bar.qml b/config/hybar/modules/Bar.qml new file mode 100644 index 0000000..46a584a --- /dev/null +++ b/config/hybar/modules/Bar.qml @@ -0,0 +1,175 @@ +import Quickshell // for PanelWindow +import QtQuick // for Text +import QtQuick.Controls +import QtQuick.Layouts +import Quickshell.Io +import Quickshell.Widgets +import Quickshell.Wayland + +PanelWindow { + anchors { + top: true + left: true + right: true + //bottom: true + + } + + id: bar + + exclusionMode: ExclusionMode.Auto + WlrLayershell.layer: WlrLayer.Background + + color: Pywal.special.background + + implicitHeight: 40 + + margins { + left: 15 + right: 15 + top: 5 + } + + + /*RowLayout { + width: bar.width + }*/ + RowLayout { + //Layout.alignment: Qt.AlignLeft | Qt.AlignVCenter + id: left + x: 0 + y: parent.y + (parent.height - height) / 2 + //width: center.x + spacing: 0 + + Launcher { + id: l + Layout.alignment: Qt.AlignLeft | Qt.AlignVCenter + Layout.preferredWidth: width + Layout.margins: 5 + } + + Workspaces { + id: ws + Layout.alignment: Qt.AlignLeft | Qt.AlignVCenter + Layout.margins: 5 + } + + /*ActiveWindow { + id: aw + Layout.margins: 5 + + Layout.maximumWidth: Math.min(implicitWidth, center.x - (parent.x + x + Layout.margins)) + }*/ + + } + + RowLayout { + //Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter + id: center + x: (parent.width - cl.width) / 2 + parent.x - centerLeft.width + //y: parent.y + (parent.height - height) / 2 + y: parent.y + (parent.height - height) / 2 + spacing: 0 + + RowLayout { + id: centerLeft + spacing: 0 + + Volume { + id: v + window: bar + popupOffset: center.x + Layout.margins: 5 + } + + Battery { + id: bat + window: bar + popupOffset: center.x + Layout.margins: 5 + } + + Hyprsunset { + id: hs + Layout.margins: 5 + } + } + + + Clock { + id: cl + Layout.margins: 5 + } + + IdleInhibitor { + id: ii + Layout.margins: 5 + } + + Wifi { + id: wifi + window: bar + Layout.margins: 5 + } + + Bluetooth { + id: bt + window: bar + popupOffset: center.x + center.width + Layout.margins: 5 + } + + } + + + RowLayout { + //Layout.alignment: Qt.AlignRight | Qt.AlignVCenter + id: right + //implicitWidth: bar.width - (spacer.x + spacer.width) + x: bar.width - implicitWidth + y: parent.y + (parent.height - height) / 2 + //Layout.maximumWidth: bar.width - (center.x + center.width) + //Layout.preferredWidth: 10 + spacing: 0 + + Media { + Layout.alignment: Qt.AlignRight | Qt.AlignVCenter + id: media + + implicitWidth: Math.min(textWidth, bar.width - (righter.width) - (center.x + center.width) - 10) + + Layout.margins: 5 + } + + RowLayout { + id: righter + spacing: 0 + Tray { + id: tray + window: bar + Layout.alignment: Qt.AlignRight | Qt.AlignVCenter + Layout.margins: 5 + popupOffset: right.x + righter.x + x + } + + Notifications { + id: notif + window: bar + Layout.alignment: Qt.AlignRight | Qt.AlignVCenter + Layout.margins: 5 + } + + Power { + id: power + window: bar + popupOffset: bar.width + Layout.alignment: Qt.AlignRight | Qt.AlignVCenter + Layout.margins: 5 + } + } + } + + + +} diff --git a/config/hybar/modules/Battery.qml b/config/hybar/modules/Battery.qml new file mode 100644 index 0000000..1fffa9c --- /dev/null +++ b/config/hybar/modules/Battery.qml @@ -0,0 +1,95 @@ +import Quickshell // for PanelWindow +import QtQuick // for Text +import QtQuick.Controls +import QtQuick.Layouts +import Quickshell.Io +import Quickshell.Widgets +import Quickshell.Hyprland +import Quickshell.Services.UPower + +ClippingWrapperRectangle { + radius: 5 + width: 100; height: 30 + color: "red" + Button { + id: button + text: if(UPower.onBattery) { + "󰁹 " + Math.floor(UPower.displayDevice.percentage * 100) + "%" + } else { + "󰂄 " + Math.floor(UPower.displayDevice.percentage * 100) + "%" + } + font.pointSize: 12 + implicitHeight: parent.height + //icon.color: "red" + //icon.source: "/nix/store/c4dcn4vl0v5njv4d587sazrad1xgyd9h-rose-pine-icon-theme-unstable-2022-09-01/share/icons/rose-pine/symbolic/devices/battery-symbolic.svg" + onClicked: { + menu.visible = true + grab.active = true + } + } + + required property var window + required property real popupOffset + id: root + + PopupWindow { + + id: menu + + anchor.window: window + anchor.rect.x: popupOffset + anchor.rect.y: 50 + implicitWidth: 250 + implicitHeight: 150 + visible: false + + color: "transparent" + + ClippingWrapperRectangle { + radius: 5 + + implicitHeight: parent.height - 20 + implicitWidth: parent.width + + ColumnLayout { + + spacing: 0 + + Button { + Layout.topMargin: 5 + x: (parent.width - width) / 2 + implicitWidth: parent.width - 10 + implicitHeight: parent.height / 5 - parent.spacing + + text: 'performance' + onClicked: PowerProfiles.profile = PowerProfile.Performance + visible: PowerProfiles.hasPerformanceProfile + } + Button { + Layout.topMargin: 5 + x: (parent.width - width) / 2 + implicitWidth: parent.width - 10 + implicitHeight: parent.height / 5 - parent.spacing + + text: 'balanced' + onClicked: PowerProfiles.profile = PowerProfile.Balanced + } + Button { + Layout.topMargin: 5 + x: (parent.width - width) / 2 + implicitWidth: parent.width - 10 + implicitHeight: parent.height / 5 - parent.spacing + + text: 'power saver' + onClicked: PowerProfiles.profile = PowerProfile.PowerSaver + } + } + } + + HyprlandFocusGrab { + id: grab + windows: [ menu ] + onCleared: menu.visible = false + } + } +} diff --git a/config/hybar/modules/Bluetooth.qml b/config/hybar/modules/Bluetooth.qml new file mode 100644 index 0000000..e59d15f --- /dev/null +++ b/config/hybar/modules/Bluetooth.qml @@ -0,0 +1,141 @@ +import Quickshell // for PanelWindow +import QtQuick // for Text +import QtQuick.Controls +import QtQuick.Layouts +import Quickshell.Io +import Quickshell.Widgets +import Quickshell.Hyprland +import Quickshell.Bluetooth + +ClippingWrapperRectangle { + + + radius: 5 + implicitWidth: 30; implicitHeight: 30 + Button { + id: button + text: "" + font.pointSize: 16 + + onClicked: { + menu.visible = true + grab.active = true + } + implicitHeight: parent.height + } + + required property PanelWindow window + required property real popupOffset + id: root + + PopupWindow { + + id: menu + + anchor.window: window + anchor.rect.x: popupOffset - width + anchor.rect.y: 50 + implicitWidth: 250 + implicitHeight: 150 + visible: false + + color: "transparent" + + ClippingWrapperRectangle { + radius: 5 + + implicitHeight: parent.height - 20 + implicitWidth: parent.width + + ColumnLayout { + + spacing: 0 + + ClippingWrapperRectangle { + radius: 5 + implicitWidth: parent.width - 2 * Layout.margins + implicitHeight: 30 + Layout.alignment: Qt.AlignHCenter | Qt.AlignTop + Layout.margins: 5 + color: "#ff3333aa" + + RowLayout { + Text { + text: 'Bluetooth' + Layout.alignment: Qt.AlignLeft | Qt.AlignVCenter + Layout.margins: 5 + } + + Switch { + Layout.alignment: Qt.AlignRight | Qt.AlignVCenter + //Layout.margins: 5 + checked: Bluetooth.defaultAdapter.enabled + onClicked: Bluetooth.defaultAdapter.enabled = checked + } + } + + } + + ScrollView { + Layout.alignment: Qt.AlignHCenter | Qt.AlignTop + Layout.margins: 5 + + implicitWidth: parent.width - 4 * Layout.margins + implicitHeight: menu.height / 2 + + id: scroll + + ColumnLayout { + spacing: 0 + + Repeater { + + id: rep + + model: Bluetooth.devices.values + + ClippingWrapperRectangle { + radius: 5 + color: "#ff3333aa" + + implicitWidth: menu.width - 3 * scroll.x + implicitHeight: 40 + + Layout.alignment: Qt.AlignHCenter | Qt.AlignTop + Layout.margins: 5 + + RowLayout { + Text { + Layout.alignment: Qt.AlignLeft | Qt.AlignVCenter + Layout.margins: 5 + + text: rep.model[index].name + } + + Button { + Layout.alignment: Qt.AlignRight | Qt.AlignVCenter + Layout.rightMargin: 5 + text: 'Connect' + + onClicked: rep.model[index].connected = !rep.model[index].connected + } + } + + + } + + } + } + + } + + } + } + + HyprlandFocusGrab { + id: grab + windows: [ menu ] + onCleared: menu.visible = false + } + } +} diff --git a/config/hybar/modules/Clock.qml b/config/hybar/modules/Clock.qml new file mode 100644 index 0000000..eeec3d7 --- /dev/null +++ b/config/hybar/modules/Clock.qml @@ -0,0 +1,27 @@ +import QtQuick // for Text +import QtQuick.Controls +import QtQuick.Layouts +import Quickshell.Widgets +import Quickshell + +Item { + implicitWidth: t.contentWidth + 10 + implicitHeight: 30 + + ClippingWrapperRectangle { + radius: 5 + anchors.fill: parent + Text { + id: t + verticalAlignment: Text.AlignVCenter + horizontalAlignment: Text.AlignHCenter + text: Qt.formatDateTime(clock.date, "dddd HH:mm:ss MM/dd/yyyy") + font.pointSize: 11 + + SystemClock { + id: clock + precision: SystemClock.Seconds + } + } + } +} diff --git a/config/hybar/modules/Hyprsunset.qml b/config/hybar/modules/Hyprsunset.qml new file mode 100644 index 0000000..1983b27 --- /dev/null +++ b/config/hybar/modules/Hyprsunset.qml @@ -0,0 +1,30 @@ +import Quickshell // for PanelWindow +import QtQuick // for Text +import QtQuick.Controls +import Quickshell.Io +import Quickshell.Widgets + +ClippingWrapperRectangle { + radius: 5 + implicitWidth: 30; height: 30 + Button { + id: button + text: "󰛨 " + font.pointSize: 16 + Process { + id: idlent + running: false + command: ["hyprsunset", "-t", "4000"] + + onExited: { + running = button.text == "󰛨 " ? false : true + } + } + + onClicked: { + idlent.running = button.text == "󰛨 " ? true : false + button.text = button.text == "󰛨 " ? "󱩌 " : "󰛨 " + } + implicitHeight: parent.height + } +} diff --git a/config/hybar/modules/IdleInhibitor.qml b/config/hybar/modules/IdleInhibitor.qml new file mode 100644 index 0000000..26e233e --- /dev/null +++ b/config/hybar/modules/IdleInhibitor.qml @@ -0,0 +1,34 @@ +import Quickshell // for PanelWindow +import QtQuick // for Text +import QtQuick.Controls +import Quickshell.Io +import Quickshell.Widgets + +ClippingWrapperRectangle { + + property real interval: 100 + id: root + + radius: 5 + implicitWidth: 30; height: 30 + Button { + id: button + text: "󰒳 " + font.pointSize: 16 + Process { + id: idlent + running: true + command: ["systemd-inhibit", "--what=idle", "sleep", root.interval.toString()] + + onExited: { + running = button.text == "󰒲 " ? false : true + } + } + + onClicked: { + idlent.running = button.text == "󰒲 " ? true : false + button.text = button.text == "󰒲 " ? "󰒳 " : "󰒲 " + } + implicitHeight: parent.height + } +} diff --git a/config/hybar/modules/Launcher.qml b/config/hybar/modules/Launcher.qml new file mode 100644 index 0000000..9bda58f --- /dev/null +++ b/config/hybar/modules/Launcher.qml @@ -0,0 +1,22 @@ +import Quickshell // for PanelWindow +import QtQuick // for Text +import QtQuick.Controls +import Quickshell.Io +import Quickshell.Widgets + +ClippingWrapperRectangle { + radius: 5 + width: 30; height: 30 + Button { + id: button + text: " " + font.pointSize: 16 + Process { + id: launcher + running: false + command: ["rofi", "-show", "drun"] + } + onClicked: launcher.running = true + implicitHeight: parent.height + } +} diff --git a/config/hybar/modules/Media.qml b/config/hybar/modules/Media.qml new file mode 100644 index 0000000..5548b00 --- /dev/null +++ b/config/hybar/modules/Media.qml @@ -0,0 +1,48 @@ +import QtQuick // for Text +import QtQuick.Controls +import QtQuick.Layouts +import Quickshell.Services.Mpris +import Quickshell.Widgets + +Item { + id: media + height: 30 + + readonly property real textWidth: info.contentWidth + 10 + + ClippingWrapperRectangle { + radius: 5 + anchors.fill: parent + Text { + + verticalAlignment: Text.AlignVCenter + horizontalAlignment: Text.AlignHCenter + + id: info + + text: { + let s = '' + let players = [] + + Mpris.players.values.forEach((p) => { + if(p.isPlaying) players.push(p) + }) + + if(players[0]?.trackTitle) { + s += players[0].trackTitle + } + if(players[0]?.trackAlbum) { + s += ' - ' + players[0].trackAlbum + } + if(players[0]?.trackArtist) { + s += ' - ' + players[0].trackArtist + } + + media.visible = players.length > 0 + + return s + } + font.pointSize: 11 + } + } +} diff --git a/config/hybar/modules/Notif.qml b/config/hybar/modules/Notif.qml new file mode 100644 index 0000000..5020629 --- /dev/null +++ b/config/hybar/modules/Notif.qml @@ -0,0 +1,71 @@ +import Quickshell +import QtQuick // for Text +import QtQuick.Controls +import QtQuick.Layouts +import Quickshell.Services.Notifications +import Quickshell.Io +import Quickshell.Widgets +import Quickshell.Hyprland + +ClippingWrapperRectangle { + id: notif + Layout.alignment: Qt.AlignHCenter | Qt.AlignTop + Layout.margins: 5 + radius: 10 + implicitWidth: parent.width - 2 * Layout.margins + implicitHeight: 100 + + color: Pywal.colors.color2 + + required property Notification src + + MouseArea { + anchors.fill: parent + + RowLayout { + Image { + //anchors.fill: parent + source: { + console.log(notif.src) + let icon = notif.src.image + if (icon.includes("?path=")) { + const [name, path] = icon.split("?path="); + icon = Qt.resolvedUrl(`${path}/${name.slice(name.lastIndexOf("/") + 1)}`); + } + return icon + } + + Layout.maximumWidth: 100 + Layout.maximumHeight: 100 + } + + ColumnLayout { + Layout.topMargin: 10 + Layout.alignment: Qt.AlignLeft | Qt.AlignTop + Text { + color: Pywal.special.background + Layout.alignment: Qt.AlignLeft | Qt.AlignTop + text: notif.src.summary + Layout.leftMargin: 10 + font.pointSize: 14 + } + Text { + color: Pywal.special.background + Layout.alignment: Qt.AlignLeft | Qt.AlignVCenter + text: notif.src.body + Layout.leftMargin: 10 + font.pointSize: 12 + } + } + } + + acceptedButtons: Qt.LeftButton | Qt.RightButton + + onClicked: mouse => { + if(mouse.button == Qt.LeftButton) { + notif.src.dismiss() + } else if(mouse.button == Qt.RightButton) { + } + } + } +} diff --git a/config/hybar/modules/Notifications.qml b/config/hybar/modules/Notifications.qml new file mode 100644 index 0000000..76bd7e1 --- /dev/null +++ b/config/hybar/modules/Notifications.qml @@ -0,0 +1,143 @@ +import Quickshell +import QtQuick // for Text +import QtQuick.Controls +import QtQuick.Layouts +import Quickshell.Services.Notifications +import Quickshell.Io +import Quickshell.Widgets +import Quickshell.Hyprland + +Item { + width: 50 + height: 30 + + ClippingWrapperRectangle { + id: barbutton + radius: 5 + anchors.fill: parent + Button { + id: button + text: "󰂚" + font.pointSize: 16 + + onClicked: { + + + menu.visible = true + grab.active = true + } + implicitHeight: parent.height + } + } + + NotificationServer { + id: server + persistenceSupported: true + imageSupported: true + actionsSupported: true + bodyImagesSupported: true + bodySupported: true + bodyHyperlinksSupported: true + inlineReplySupported: true + actionIconsSupported: true + + onNotification: (n) => { + n.tracked = true + } + + + } + + required property PanelWindow window + id: root + + PopupWindow { + + id: menu + + anchor.window: window + anchor.rect.x: window.width - width + anchor.rect.y: 50 + implicitWidth: 400 + implicitHeight: 1080 - anchor.rect.y + visible: false + + color: "transparent" + + ClippingWrapperRectangle { + radius: 5 + + color: Pywal.special.background + + implicitHeight: parent.height - 20 + implicitWidth: parent.width + + ColumnLayout { + id: lay + + spacing: 10 + + ClippingWrapperRectangle { + color: Pywal.colors.color2 + radius: 5 + Layout.margins: 5 + Layout.alignment: Qt.AlignVCenter | Qt.AlignTop + implicitWidth: menu.width - 2 * Layout.margins + + RowLayout { + width: parent.width + Text { + color: Pywal.colors.color0 + Layout.margins: 5 + Layout.alignment: Qt.AlignLeft | Qt.AlignVCenter + text: 'Notifications' + } + Button { + Layout.alignment: Qt.AlignRight | Qt.AlignVCenter + Layout.margins: 5 + implicitWidth: 20 + implicitHeight: 20 + + text: 'x' + + onClicked: { + while(server.trackedNotifications.values.length > 0) { + server.trackedNotifications.values[0].dismiss() + } + } + } + } + } + + ColumnLayout { + Layout.alignment: Qt.AlignVCenter | Qt.AlignTop + Repeater { + id: rep + + model: server.trackedNotifications.values + + Notif { + required property int index + src: rep.model[index] + } + + onItemAdded: (idx, it) => { + button.text = '󱅫 ' + rep.count + } + + onItemRemoved: (idx, it) => { + button.text = (rep.count - 1) <= 0 ? "󰂚" : '󱅫 ' + (rep.count - 1) + } + } + } + + } + } + + HyprlandFocusGrab { + id: grab + windows: [ menu ] + onCleared: menu.visible = false + } + } +} diff --git a/config/hybar/modules/Power.qml b/config/hybar/modules/Power.qml new file mode 100644 index 0000000..51b7775 --- /dev/null +++ b/config/hybar/modules/Power.qml @@ -0,0 +1,120 @@ +import Quickshell +import QtQuick // for Text +import QtQuick.Controls +import QtQuick.Layouts +import Quickshell.Hyprland +import Quickshell.Io +import Quickshell.Widgets + +Item { + width: 30 + height: 30 + + id: root + + required property PanelWindow window + required property real popupOffset + + ClippingWrapperRectangle { + radius: 5 + width: 30; height: 30 + Button { + id: button + text: " " + font.pointSize: 16 + + onClicked: { + menu.visible = true + grab.active = true + } + implicitHeight: parent.height + } + } + + PopupWindow { + + id: menu + + anchor.window: window + anchor.rect.x: popupOffset + anchor.rect.y: 50 + implicitWidth: 150 + implicitHeight: 250 + visible: false + + color: "transparent" + + ClippingWrapperRectangle { + radius: 5 + + implicitHeight: parent.height - 20 + implicitWidth: parent.width + + ColumnLayout { + + spacing: 0 + + Button { + Layout.topMargin: 5 + x: (parent.width - width) / 2 + implicitWidth: parent.width - 10 + implicitHeight: parent.height / 5 - parent.spacing + + text: 'shutdown' + onClicked: shutdown.running = true + Process { + id: shutdown + running: false + command: ["systemctl", "poweroff"] + } + } + + Button { + x: (parent.width - width) / 2 + implicitWidth: parent.width - 10 + implicitHeight: parent.height / 5 - parent.spacing + text: 'reboot' + onClicked: reboot.running = true + Process { + id: reboot + running: false + command: ["systemctl", "reboot"] + } + } + + Button { + x: (parent.width - width) / 2 + implicitWidth: parent.width - 10 + implicitHeight: parent.height / 5 - parent.spacing + text: 'logout' + onClicked: logout.running = true + Process { + id: logout + running: false + command: ["loginctl", "kill-session", "self" ] + } + } + + Button { + Layout.bottomMargin: 10 + x: (parent.width - width) / 2 + implicitWidth: parent.width - 10 + implicitHeight: parent.height / 5 - parent.spacing + text: 'sleep' + onClicked: sleep.running = true + Process { + id: sleep + running: false + command: ["systemctl", "sleep"] + } + } + } + } + + HyprlandFocusGrab { + id: grab + windows: [ menu ] + onCleared: menu.visible = false + } + } +} diff --git a/config/hybar/modules/Pywal.qml b/config/hybar/modules/Pywal.qml new file mode 100644 index 0000000..957ef03 --- /dev/null +++ b/config/hybar/modules/Pywal.qml @@ -0,0 +1,58 @@ +pragma Singleton + +import Quickshell +import Quickshell.Io + +Singleton { + + property string wallpaper: json.wallpaper + + property string alpha: json.alpha + + property JsonObject special: json.special + property JsonObject colors: json.colors + + FileView { + + path: "/home/nathan/.cache/wal/colors.json" + + watchChanges: true + + onFileChanged: reload() + + JsonAdapter { + id: json + property string wallpaper: "/home/nathan/Pictures/Wallpaper/bluescape.jpg" + + property string alpha: "100" + + property JsonObject special: JsonObject { + property string background: "white" + property string foreground: "white" + property string cursor: "white" + } + + property JsonObject colors: JsonObject { + property string color0: "white" + property string color1: "white" + property string color2: "white" + property string color3: "white" + + property string color4: "white" + property string color5: "white" + property string color6: "white" + property string color7: "white" + + property string color8: "white" + property string color9: "white" + property string color10: "white" + property string color11: "white" + + property string color12: "white" + property string color13: "white" + property string color14: "white" + property string color15: "white" + } + } + } +} diff --git a/config/hybar/modules/Tray.qml b/config/hybar/modules/Tray.qml new file mode 100644 index 0000000..f4c7e47 --- /dev/null +++ b/config/hybar/modules/Tray.qml @@ -0,0 +1,62 @@ +import QtQuick // for Text +import QtQuick.Controls +import QtQuick.Layouts +import Quickshell.Services.SystemTray +import Quickshell.Widgets + +Item { + implicitWidth: 10 + rep.count * (2 * lay.spacing + 20) + height: 30 + visible: SystemTray.items.values.length != 0 + + id: root + required property var window + required property real popupOffset + + ClippingWrapperRectangle { + radius: 5 + anchors.fill: parent + RowLayout { + id: lay + spacing: 4 + Repeater { + id: rep + + model: SystemTray.items + ClippingWrapperRectangle { + Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter + radius: 10 + implicitWidth: 20 + implicitHeight: 20 + MouseArea { + anchors.fill: parent + + Image { + anchors.fill: parent + source: { + let icon = SystemTray.items.values[index].icon + if (icon.includes("?path=")) { + const [name, path] = icon.split("?path="); + icon = Qt.resolvedUrl(`${path}/${name.slice(name.lastIndexOf("/") + 1)}`); + } + return icon + } + } + + acceptedButtons: Qt.LeftButton | Qt.RightButton + + onClicked: (mouse) => { + if(mouse.button == Qt.LeftButton) { + SystemTray.items.values[index].activate() + } else if(mouse.button == Qt.RightButton) { + SystemTray.items.values[index].display(root.window, popupOffset, 40) + } + } + } + } + } + } + + + } +} diff --git a/config/hybar/modules/Volume.qml b/config/hybar/modules/Volume.qml new file mode 100644 index 0000000..b43778c --- /dev/null +++ b/config/hybar/modules/Volume.qml @@ -0,0 +1,107 @@ +import Quickshell // for PanelWindow +import QtQuick // for Text +import QtQuick.Controls +import QtQuick.Layouts +import Quickshell.Io +import Quickshell.Widgets +import Quickshell.Hyprland +import Quickshell.Services.Pipewire + +ClippingWrapperRectangle { + radius: 5 + width: 100; height: 30 + Button { + id: button + text: (Pipewire.defaultAudioSink?.audio?.muted ? " " : " ") + Math.floor(Pipewire.defaultAudioSink?.audio?.volume * 100) + "%" + font.pointSize: 12 + implicitHeight: parent.height + + PwObjectTracker { + objects: [ Pipewire.defaultAudioSink ] + } + + onClicked: { + menu.visible = true + grab.active = true + } + + } + + required property var window + required property real popupOffset + id: root + + PopupWindow { + + id: menu + + anchor.window: window + anchor.rect.x: popupOffset + anchor.rect.y: 50 + implicitWidth: 250 + implicitHeight: 150 + visible: false + + color: "transparent" + + ClippingWrapperRectangle { + radius: 5 + + implicitHeight: parent.height - 20 + implicitWidth: parent.width + + ScrollView { + ColumnLayout { + + spacing: 0 + + Text { + text: 'Output Devices' + } + + ColumnLayout { + Repeater { + id: outputs + + model: { + Pipewire.nodes.values.filter(n => n.isSink && n.audio && n.nickname != "") + } + + Button { + text: outputs.model[index].nickname + onClicked: Pipewire.preferredDefaultAudioSink = outputs.model[index] + } + } + } + + Text { + text: 'Input Devices' + } + + ColumnLayout { + Repeater { + id: inputs + + model: { + Pipewire.nodes.values.filter(n => !n.isSink && n.audio && n.nickname != "") + } + + Button { + text: inputs.model[index].nickname + onClicked: Pipewire.preferredDefaultAudioSource = inputs.model[index] + } + } + } + + } + } + + } + + HyprlandFocusGrab { + id: grab + windows: [ menu ] + onCleared: menu.visible = false + } + } +} diff --git a/config/hybar/modules/Wifi.qml b/config/hybar/modules/Wifi.qml new file mode 100644 index 0000000..99a66af --- /dev/null +++ b/config/hybar/modules/Wifi.qml @@ -0,0 +1,72 @@ +import Quickshell +import QtQuick // for Text +import QtQuick.Controls +import QtQuick.Layouts +import Quickshell.Hyprland +import Quickshell.Io +import Quickshell.Widgets + +Item { + implicitWidth: 30 + implicitHeight: 30 + + ClippingWrapperRectangle { + radius: 5 + anchors.fill: parent + Button { + id: button + text: "󰤨 " + font.pointSize: 16 + + onClicked: { + menu.visible = true + grab.active = true + } + implicitHeight: parent.height + } + } + + property var window: null + id: root + + PopupWindow { + + id: menu + + anchor.window: window + anchor.rect.x: root.parent.x + root.parent.width - width + anchor.rect.y: 50 + implicitWidth: 250 + implicitHeight: 150 + visible: false + + color: "transparent" + + ClippingWrapperRectangle { + radius: 5 + + implicitHeight: parent.height - 20 + implicitWidth: parent.width + + ColumnLayout { + + spacing: 0 + + Button { + Layout.topMargin: 5 + x: (parent.width - width) / 2 + implicitWidth: parent.width - 10 + implicitHeight: parent.height / 5 - parent.spacing + + text: 'shutdown' + } + } + } + + HyprlandFocusGrab { + id: grab + windows: [ menu ] + onCleared: menu.visible = false + } + } +} diff --git a/config/hybar/modules/Workspaces.qml b/config/hybar/modules/Workspaces.qml new file mode 100644 index 0000000..353c952 --- /dev/null +++ b/config/hybar/modules/Workspaces.qml @@ -0,0 +1,47 @@ +import QtQuick // for Text +import QtQuick.Controls +import QtQuick.Layouts +import Quickshell.Hyprland +import Quickshell.Widgets + +Item { + implicitWidth: 10 + rep.count * (2 * lay.spacing + 25) + implicitHeight: 30 + + Component.onCompleted: Hyprland.refreshWorkspaces() + + ClippingWrapperRectangle { + color: Pywal.colors.color2 + radius: 5 + anchors.fill: parent + RowLayout { + id: lay + Repeater { + id: rep + + property var ws: { + let arr = []; + Hyprland.workspaces.values.forEach((w) => { if(w.id > 0) arr.push(w) }) + return arr; + } + + model: ws + ClippingWrapperRectangle { + Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter + radius: 10 + implicitWidth: 25 + Button { + background: Rectangle { + color: Hyprland.focusedWorkspace.id == rep.model[index].id ? Pywal.colors.color6 : Pywal.colors.color4 + anchors.fill: parent + } + text: rep.model[index].id + onClicked: rep.model[index].activate() + } + } + } + } + + + } +} diff --git a/config/hybar/shell.qml b/config/hybar/shell.qml new file mode 100644 index 0000000..5f076d4 --- /dev/null +++ b/config/hybar/shell.qml @@ -0,0 +1,15 @@ +//@ pragma Env QS_NO_RELOAD_POPUP=1 +//@ pragma Env QSG_RENDER_LOOP=threaded +//@ pragma Env QT_QUICK_FLICKABLE_WHEEL_DECELERATION=10000 + +//@ pragma UseQApplication + +import Quickshell // for ShellRoot +import qs.modules + +ShellRoot { + Bar { + id: bar + //visible: false + } +} diff --git a/dev/shells.nix b/dev/shells.nix new file mode 100644 index 0000000..a42e3b9 --- /dev/null +++ b/dev/shells.nix @@ -0,0 +1,19 @@ +{ ... }: { + + + perSystem = { pkgs, system, ... }: { + + devShells.default = pkgs.mkShellNoCC { + + nativeBuildInputs = with pkgs; [ + quickshell + ]; + + shellHook = '' + export SHELL=$(realpath `which zsh`) + + exec nvim + ''; + }; + }; +} diff --git a/dev/systems.nix b/dev/systems.nix new file mode 100644 index 0000000..0dd7e9b --- /dev/null +++ b/dev/systems.nix @@ -0,0 +1,7 @@ +{ ... }: { + + systems = [ + "x86_64-linux" + "aarch64-linux" + ]; +} diff --git a/flake.lock b/flake.lock new file mode 100644 index 0000000..b30d737 --- /dev/null +++ b/flake.lock @@ -0,0 +1,77 @@ +{ + "nodes": { + "flake-parts": { + "inputs": { + "nixpkgs-lib": "nixpkgs-lib" + }, + "locked": { + "lastModified": 1772408722, + "narHash": "sha256-rHuJtdcOjK7rAHpHphUb1iCvgkU3GpfvicLMwwnfMT0=", + "owner": "hercules-ci", + "repo": "flake-parts", + "rev": "f20dc5d9b8027381c474144ecabc9034d6a839a3", + "type": "github" + }, + "original": { + "owner": "hercules-ci", + "repo": "flake-parts", + "type": "github" + } + }, + "import-tree": { + "locked": { + "lastModified": 1772344373, + "narHash": "sha256-OQQ1MhB9t1J71b2wxRRTdH/Qd8UGG0p+dGspfCf5U1c=", + "owner": "vic", + "repo": "import-tree", + "rev": "10fda59eee7d7970ec443b925f32a1bc7526648c", + "type": "github" + }, + "original": { + "owner": "vic", + "repo": "import-tree", + "type": "github" + } + }, + "nixpkgs": { + "locked": { + "lastModified": 1772433332, + "narHash": "sha256-izhTDFKsg6KeVBxJS9EblGeQ8y+O8eCa6RcW874vxEc=", + "owner": "nixos", + "repo": "nixpkgs", + "rev": "cf59864ef8aa2e178cccedbe2c178185b0365705", + "type": "github" + }, + "original": { + "owner": "nixos", + "ref": "nixos-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixpkgs-lib": { + "locked": { + "lastModified": 1772328832, + "narHash": "sha256-e+/T/pmEkLP6BHhYjx6GmwP5ivonQQn0bJdH9YrRB+Q=", + "owner": "nix-community", + "repo": "nixpkgs.lib", + "rev": "c185c7a5e5dd8f9add5b2f8ebeff00888b070742", + "type": "github" + }, + "original": { + "owner": "nix-community", + "repo": "nixpkgs.lib", + "type": "github" + } + }, + "root": { + "inputs": { + "flake-parts": "flake-parts", + "import-tree": "import-tree", + "nixpkgs": "nixpkgs" + } + } + }, + "root": "root", + "version": 7 +} diff --git a/flake.nix b/flake.nix new file mode 100644 index 0000000..b9d34c6 --- /dev/null +++ b/flake.nix @@ -0,0 +1,16 @@ +{ + description = "A flake to package/run this quickshell config"; + + inputs = { + nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable"; + + flake-parts.url = "github:hercules-ci/flake-parts"; + + import-tree.url = "github:vic/import-tree"; + + }; + + outputs = { ... } @ inputs: + inputs.flake-parts.lib.mkFlake { inherit inputs; } + (inputs.import-tree [ ./dev ./config ]); +}