From 7c8f579ef9a3c3ded888405a4810cd4aa889feaf Mon Sep 17 00:00:00 2001 From: L-Nafaryus Date: Sun, 21 Jul 2024 17:14:58 +0500 Subject: [PATCH] astora: replace eww with ags config: remove eww new: lib.preconfiguredModules: homeManager module ags --- config/eww/eww-helper.py | 50 --- config/eww/eww.scss | 50 --- config/eww/eww.yuck | 84 ---- lib/default.nix | 1 + .../homeManager/ags/ags/config.js | 404 ++++++++++++++++++ .../homeManager/ags/default.nix | 9 + .../homeManager/default.nix | 3 + nixosConfigurations/astora/users.nix | 17 +- nixosConfigurations/default.nix | 2 +- 9 files changed, 426 insertions(+), 194 deletions(-) delete mode 100755 config/eww/eww-helper.py delete mode 100644 config/eww/eww.scss delete mode 100644 config/eww/eww.yuck create mode 100644 lib/preconfiguredModules/homeManager/ags/ags/config.js create mode 100644 lib/preconfiguredModules/homeManager/ags/default.nix create mode 100644 lib/preconfiguredModules/homeManager/default.nix diff --git a/config/eww/eww-helper.py b/config/eww/eww-helper.py deleted file mode 100755 index 0108349..0000000 --- a/config/eww/eww-helper.py +++ /dev/null @@ -1,50 +0,0 @@ -#!/usr/bin/env python3 - -import click -import subprocess -import json - -@click.group() -def cli(): - pass - -@cli.command() -def xkblayout(): - p = subprocess.run("hyprctl devices -j", capture_output = True, shell = True) - devices = json.loads(p.stdout) - - for keyboard in devices["keyboards"]: - if keyboard["name"] == "keychron-keychron-k3-pro": - click.echo(keyboard["active_keymap"][ :2].lower(), nl = False) - -@cli.command() -@click.option("--action", "-a", type = click.Choice(["buttons", "current", "count"])) -def workspace(action): - p = subprocess.run("hyprctl workspaces -j", capture_output = True, shell = True) - workspaces = json.loads(p.stdout) - p = subprocess.run("hyprctl activeworkspace -j", capture_output = True, shell = True) - current_workspace = json.loads(p.stdout) - - match action: - case "buttons": - buttons = "" - for workspace in workspaces: - css = ':css "button {background-color: #3b4261}"' if workspace["id"] == current_workspace["id"] else "" - buttons += '(button {} :width "40" :onclick "hyprctl dispatch workspace {}" "{}") ' \ - .format(css, workspace["id"], workspace["id"]) - click.echo(f'(box {buttons})', nl = False) - case "current": - click.echo(current_workspace["id"], nl = False) - case "count": - click.echo(len(workspaces), nl = False) - -@cli.command() -def get_volume(): - p = subprocess.run("wpctl get-volume @DEFAULT_AUDIO_SINK@", capture_output = True, shell = True) - volume_status = p.stdout.decode().replace("\n", "").split(" ") - volume = volume_status[1] - icon = "" if volume_status[-1] == "[MUTED]" else "" - click.echo(f"{volume} {icon}", nl = False) - -if __name__ == "__main__": - cli() diff --git a/config/eww/eww.scss b/config/eww/eww.scss deleted file mode 100644 index 4513488..0000000 --- a/config/eww/eww.scss +++ /dev/null @@ -1,50 +0,0 @@ -* { - all: unset; - -} - -.topbar { - background-color: #1f2335; - color: #c0caf5; -} - -/*button { - background-color: #24283b; - color: #c0caf5; - border-radius: 5px; - padding: 4px 20px; - border: 2px solid #3b4261; -}*/ - -button:hover { - background-color: #3b4261; - transition: 0.5s; -} - -.power-button { - background-color: #ff9e64; - border-style: solid; - border-left: 2px; - border-color: #3b4261; -} - -.powermenu-block { - background-color: #689d6a; - color: #ebdbb2; - margin: 100px; - color: #c0caf5; -} - -.powermenu { - background-color: #1f2335; - border: 2px solid #3b4261; - border-radius: 5px; - font-size: 18px; -} - -.systray-block { - background-color: #ffffff; - color: #aaaaaa; - border: 2px solid #3b4261; - border-radius: 5px; -} diff --git a/config/eww/eww.yuck b/config/eww/eww.yuck deleted file mode 100644 index 5981592..0000000 --- a/config/eww/eww.yuck +++ /dev/null @@ -1,84 +0,0 @@ - -(defpoll time :interval "5s" "date '+%H:%M'") -(defpoll date :interval "5s" "date '+%b %d, %Y'") -(defpoll workspace_buttons :interval "1s" "~/.config/eww/eww-helper.py workspace -a buttons") -(defpoll language :interval "1s" "~/.config/eww/eww-helper.py xkblayout") -(defpoll volume :interval "1s" "~/.config/eww/eww-helper.py get-volume") - -(defwidget workspaces [] - (literal :valign "center" :content workspace_buttons) -) -(defwidget closer [window] - (eventbox :onclick "eww close ${window} ${window}-closer")) - - -(defwindow powermenu - :monitor "Q27G2G3R3B" - :stacking "fg" - :exclusive false - :focusable false - :geometry (geometry :anchor "top right" :x "5px" :y "5px" :width "120px" :height "100px") - (eventbox :onhoverlost "eww close powermenu" - (box :orientation "h" :spacing 8 - (box :orientation "v" :spacing 8 - (button :css "button {color: #ff9e64;}" :tooltip "Poweoff" :onclick "systemctl poweroff" "󰐥") - (button :tooltip "Reboot" :onclick "systemctl reboot" "󰑐") - ) - (box :orientation "v" :spacing 8 - (button :tooltip "Suspend" :onclick "systemctl suspend" "󰏧") - (button :tooltip "Logout" "󰍃") - ) - ) - ) -) - -(defwindow calendar - :monitor "Q27G2G3R3B" - :stacking "fg" - :exclusive false - :focusable false - :geometry (geometry :anchor "top center" :x "5px" :y "5px" :width "120px" :height "100px") - (eventbox :onhoverlost "eww close calendar" - (box :orientation "h" :spacing 8 - (calendar) - ) - ) -) - -(defwindow powermenu-closer - :monitor "Q27G2G3R3B" - :stacking "fg" - :focusable false - :geometry (geometry :width "100%" :height "100%") - (closer :window "powermenu") -) - -(deflisten player :initial "" "playerctl --follow metadata --format '{{ artist }} - {{ title }}' || true") - -(defwindow topbar - :monitor "Q27G2G3R3B" - :stacking "fg" - :exclusive true - :focusable false - :geometry (geometry :anchor "top center" :x "0%" :y "0%" :width "100%" :height "30px") - (box :orientation "h" :halign "fill" - (box :orientation "h" :halign "start" :space-evenly false :spacing 20 - (box :space-evenly false (workspaces :orientation "h" :halign "start" :valign "center")) - (label :limit-width 50 :text {player != "" ? "${player}" : ""}) - ) - (box :orientation "h" :halign "center" - (button :width 100 :halign "center" :onclick "eww open --toggle calendar" time) - ) - (box :orientation "h" :halign "end" :spacing 20 :space-evenly false - ;;(box (scale :min 100 :max 100 :value 50 :orientation "h")) - ;;(box :style "power-button" :width "100px" (circular-progress :value 50)) - - (label :width 20 :text language) - (label :width 20 :text volume) - (systray :prepend-new true :spacing 20) - (label :text date :halign "center") - (button :width 50 :onclick "eww open --toggle powermenu" "󰐥") - ) - ) -) - diff --git a/lib/default.nix b/lib/default.nix index ad1cc85..7d44f0c 100644 --- a/lib/default.nix +++ b/lib/default.nix @@ -12,6 +12,7 @@ }) [ ./preconfiguredModules/bonvim.nix + ./preconfiguredModules/homeManager ]); isBroken = derivation: derivation ? meta && derivation.meta ? broken && derivation.meta.broken; diff --git a/lib/preconfiguredModules/homeManager/ags/ags/config.js b/lib/preconfiguredModules/homeManager/ags/ags/config.js new file mode 100644 index 0000000..d491fe8 --- /dev/null +++ b/lib/preconfiguredModules/homeManager/ags/ags/config.js @@ -0,0 +1,404 @@ +const hyprland = await Service.import("hyprland") +const notifications = await Service.import("notifications") +//const mpris = await Service.import("mpris") +const audio = await Service.import("audio") +const battery = await Service.import("battery") +const systemtray = await Service.import("systemtray") + +const date = Variable("", { + poll: [1000, 'date "+%H:%M:%S %b %e, %Y"'], +}) + +function Clock() { + return Widget.Label({ + css: "font-size: 24px; padding: 16px;", + label: date.bind().as(d => ` ${d}`), + }) +} + +function Volume() { + const icons = { + 101: "overamplified", + 67: "high", + 34: "medium", + 1: "low", + 0: "muted", + } + + function getIcon() { + const icon = audio.speaker.is_muted ? 0 : [101, 67, 34, 1, 0].find( + threshold => threshold <= audio.speaker.volume * 100) + + return `audio-volume-${icons[icon]}-symbolic` + } + + const icon = Widget.Icon({ + icon: Utils.watch(getIcon(), audio.speaker, getIcon), + }) + + const slider = Widget.Slider({ + hexpand: true, + draw_value: false, + vertical: true, + on_change: ({ value }) => audio.speaker.volume = value, + setup: self => self.hook(audio.speaker, () => { + self.value = audio.speaker.volume || 0 + }), + }) + + return Widget.Box({ + class_name: "volume", + css: "min-width: 180px", + children: [icon, slider], + }) +} + +//const players = mpris.bind("players") + +const FALLBACK_ICON = "audio-x-generic-symbolic" +const PLAY_ICON = "media-playback-start-symbolic" +const PAUSE_ICON = "media-playback-pause-symbolic" +const PREV_ICON = "media-skip-backward-symbolic" +const NEXT_ICON = "media-skip-forward-symbolic" + +/** @param {number} length */ +function lengthStr(length) { + const min = Math.floor(length / 60) + const sec = Math.floor(length % 60) + const sec0 = sec < 10 ? "0" : "" + return `${min}:${sec0}${sec}` +} + +/** @param {import('types/service/mpris').MprisPlayer} player */ +function Player(player) { + const img = Widget.Box({ + class_name: "img", + vpack: "start", + css: player.bind("cover_path").transform(p => ` + background-image: url('${p}'); + `), + }) + + const title = Widget.Label({ + class_name: "title", + wrap: true, + hpack: "start", + label: player.bind("track_title"), + }) + + const artist = Widget.Label({ + class_name: "artist", + wrap: true, + hpack: "start", + label: player.bind("track_artists").transform(a => a.join(", ")), + }) + + const positionSlider = Widget.Slider({ + class_name: "position", + draw_value: false, + on_change: ({ value }) => player.position = value * player.length, + visible: player.bind("length").as(l => l > 0), + setup: self => { + function update() { + const value = player.position / player.length + self.value = value > 0 ? value : 0 + } + self.hook(player, update) + self.hook(player, update, "position") + self.poll(1000, update) + }, + }) + + const positionLabel = Widget.Label({ + class_name: "position", + hpack: "start", + setup: self => { + const update = (_, time) => { + self.label = lengthStr(time || player.position) + self.visible = player.length > 0 + } + + self.hook(player, update, "position") + self.poll(1000, update) + }, + }) + + const lengthLabel = Widget.Label({ + class_name: "length", + hpack: "end", + visible: player.bind("length").transform(l => l > 0), + label: player.bind("length").transform(lengthStr), + }) + + const icon = Widget.Icon({ + class_name: "icon", + hexpand: true, + hpack: "end", + vpack: "start", + tooltip_text: player.identity || "", + icon: player.bind("entry").transform(entry => { + const name = `${entry}-symbolic` + return Utils.lookUpIcon(name) ? name : FALLBACK_ICON + }), + }) + + const playPause = Widget.Button({ + class_name: "play-pause", + on_clicked: () => player.playPause(), + visible: player.bind("can_play"), + child: Widget.Icon({ + icon: player.bind("play_back_status").transform(s => { + switch (s) { + case "Playing": return PAUSE_ICON + case "Paused": + case "Stopped": return PLAY_ICON + } + }), + }), + }) + + const prev = Widget.Button({ + on_clicked: () => player.previous(), + visible: player.bind("can_go_prev"), + child: Widget.Icon(PREV_ICON), + }) + + const next = Widget.Button({ + on_clicked: () => player.next(), + visible: player.bind("can_go_next"), + child: Widget.Icon(NEXT_ICON), + }) + + return Widget.Box( + { class_name: "player" }, + img, + Widget.Box( + { + vertical: true, + hexpand: true, + }, + Widget.Box([ + title, + icon, + ]), + artist, + Widget.Box({ vexpand: true }), + positionSlider, + Widget.CenterBox({ + start_widget: positionLabel, + center_widget: Widget.Box([ + prev, + playPause, + next, + ]), + end_widget: lengthLabel, + }), + ), + ) +} + +function Media() { + return Widget.Box({ + vertical: true, + css: "min-height: 2px; min-width: 2px;", + visible: players.as(p => p.length > 0), + children: players.as(p => p.map(Player)), + }) +} + +function SysTray() { + const items = systemtray.bind("items") + .as(items => items.map(item => Widget.Button({ + css: "padding: 14px 16px; border: 2px solid #b7bdf8; border-radius: 50%", + child: Widget.Icon({ icon: item.bind("icon") }), + on_primary_click: (_, event) => item.activate(event), + on_secondary_click: (_, event) => item.openMenu(event), + tooltip_markup: item.bind("tooltip_markup"), + }))) + + return Widget.Box({ + css: "padding: 10px", + spacing: 8, + children: items, + }) +} + + +function Workspaces() { + const activeId = hyprland.active.workspace.bind("id") + const workspaces = hyprland.bind("workspaces") + .as(ws => ws.map(({ id }) => Widget.Button({ + css: "margin: 4px 4px; border: 2px solid #b7bdf8; border-radius: 5px;", + on_clicked: () => hyprland.messageAsync(`dispatch workspace ${id}`), + child: Widget.Label({ + css: "padding: 11px 16px; font-size: 20px;", + label: `${id}` + }), + class_name: activeId.as(i => `${i === id ? "focused" : ""}`), + }))) + + return Widget.Box({ + css: "padding: 1px 1px; ", + class_name: "workspaces", + children: workspaces, + }) +} + + + +App.config({ + windows: [ + Widget.Window({ + name: "clock", + visible: false, + anchor: ["top"], + margins: [64, 64], + child: Clock() + }), + Widget.Window({ + name: "control", + visible: false, + anchor: ["top"], + margins: [128, 64], + css: "all: unset; background-color: rgba(0, 0, 0, 0)", + child: Widget.Box({ + hpack: "center", + spacing: 8, + children: [ + Widget.Button({ + css: "padding: 14px 20px; color: #f5a97f; border: 2px solid #b7bdf8; border-radius: 50%", + child: Widget.Label("󰐥"), + onClicked: () => Utils.exec("systemctl poweroff") + }), + Widget.Button({ + css: "padding: 14px 20px; border: 2px solid #b7bdf8; border-radius: 50%", + child: Widget.Label("󰑓"), + onClicked: () => Utils.exec("systemctl reboot") + }), + Widget.Button({ + css: "padding: 14px 20px; border: 2px solid #b7bdf8; border-radius: 50%", + child: Widget.Label("󰒲"), + onClicked: () => Utils.exec("systemctl suspend") + }), + Widget.Button({ + css: "padding: 14px 20px; border: 2px solid #b7bdf8; border-radius: 50%", + child: Widget.Label("󰍃"), + onClicked: () => Utils.exec("loginctl terminate-user $USER") + }), + ] + }) + }), + Widget.Window({ + name: "systray", + visible: false, + anchor: ["top", "right"], + margins: [64, 64], + css: "all: unset; background-color: rgba(0, 0, 0, 0)", + child: SysTray() + }), + Widget.Window({ + name: "workspaces", + visible: false, + anchor: ["bottom"], + margins: [64, 64], + css: "all: unset; background-color: rgba(0, 0, 0, 0)", + child: Workspaces() + }), + Widget.Window({ + name: "window-title", + visible: false, + anchor: ["bottom"], + margins: [128, 64], + css: "all: unset; background-color: rgba(0, 0, 0, 0)", + child: Widget.Label({ + css: "color: #c6a0f6; padding: 1px 1px", + label: hyprland.active.client.bind("title") + }) + }) + ], +}) + +App.applyCss(` + window { + background-color: #24273a; + opacity: 0.95; + color: #cad3f5; + border: 2px solid #b7bdf8; + border-radius: 5px; + } + + menu { + background-color: #24273a; + + } + + button { + all: unset; + font-size: 20px; + background-color: #24273a; + border-style: solid; + border-left: 2px; + border-color: #3b4261; + } + + button:hover { + background-color: #3b4261; + transition: 0.5s; + } + + .workspaces button.focused { + background-color: #494d64; + } + + .player { + padding: 10px; + min-width: 350px; + } + + .player .img { + min-width: 100px; + min-height: 100px; + background-size: cover; + background-position: center; + border-radius: 13px; + margin-right: 1em; + } + + .player .title { + font-size: 1.2em; + } + + .player .artist { + font-size: 1.1em; + color: @insensitive_fg_color; + } + + .player scale.position { + padding: 0; + margin-bottom: .3em; + } + + .player scale.position trough { + min-height: 8px; + } + + .player scale.position highlight { + background-color: @theme_fg_color; + } + + .player scale.position slider { + all: unset; + } + + .player button { + min-height: 1em; + min-width: 1em; + padding: .3em; + } + + .player button.play-pause { + margin: 0 .3em; + } +`) + +export {} diff --git a/lib/preconfiguredModules/homeManager/ags/default.nix b/lib/preconfiguredModules/homeManager/ags/default.nix new file mode 100644 index 0000000..4669014 --- /dev/null +++ b/lib/preconfiguredModules/homeManager/ags/default.nix @@ -0,0 +1,9 @@ +{pkgs, ...}: { + programs.ags = { + enable = true; + extraPackages = with pkgs; [ + libdbusmenu-gtk3 # for system tray + ]; + configDir = ./ags; + }; +} diff --git a/lib/preconfiguredModules/homeManager/default.nix b/lib/preconfiguredModules/homeManager/default.nix new file mode 100644 index 0000000..88722cf --- /dev/null +++ b/lib/preconfiguredModules/homeManager/default.nix @@ -0,0 +1,3 @@ +{ + ags = import ./ags; +} diff --git a/nixosConfigurations/astora/users.nix b/nixosConfigurations/astora/users.nix index 66f0390..2b79a07 100644 --- a/nixosConfigurations/astora/users.nix +++ b/nixosConfigurations/astora/users.nix @@ -3,6 +3,7 @@ pkgs, lib, bonPkgs, + bonLib, inputs, ... }: { @@ -30,6 +31,7 @@ imports = [ inputs.catppuccin.homeManagerModules.catppuccin inputs.ags.homeManagerModules.default + bonLib.preconfiguredModules.homeManager.ags ]; home.packages = with pkgs; [ #gnupg @@ -99,7 +101,6 @@ steamtinkerlaunch - eww tor networkmanagerapplet #rofi-wayland @@ -264,12 +265,6 @@ }; }; }; - ags = { - enable = true; - extraPackages = with pkgs; [ - libdbusmenu-gtk3 # for system tray - ]; - }; obs-studio = { enable = true; @@ -335,7 +330,7 @@ ]; exec-once = [ - "eww daemon" + "ags &" "nm-applet --indicator &" "blueman-applet &" "wl-gammarelay-rs run &" @@ -449,7 +444,11 @@ "SUPER, Q, exec, $terminal" "SUPER, N, exec, $fileManager" "SUPER, R, exec, $menu" - "SUPER, P, exec, eww open --toggle basemenu" + "SUPER, X, exec, ags -t clock" + "SUPER, X, exec, ags -t control" + "SUPER, X, exec, ags -t systray" + "SUPER, X, exec, ags -t workspaces" + "SUPER, X, exec, ags -t window-title" "SUPER, C, killactive," "SUPER, M, exit," diff --git a/nixosConfigurations/default.nix b/nixosConfigurations/default.nix index 5310279..8438642 100644 --- a/nixosConfigurations/default.nix +++ b/nixosConfigurations/default.nix @@ -14,7 +14,7 @@ ./astora ]; specialArgs = { - inherit inputs; + inherit inputs bonLib; bonPkgs = self.packages.x86_64-linux; }; };