From 8ea1207bb9bd3520bf59eaaa00a56eb79c308811 Mon Sep 17 00:00:00 2001 From: Sweetbread Date: Fri, 27 Dec 2024 15:42:51 +0300 Subject: [PATCH] feat: ags --- flake.lock | 224 ++------- flake.nix | 20 +- home-manager/modules/ags.nix | 327 +------------ home-manager/modules/ags/README.md | 24 +- home-manager/modules/ags/app.ts | 13 + home-manager/modules/ags/config.js | 219 --------- home-manager/modules/ags/style.scss | 106 ++++ home-manager/modules/ags/widget/Bar.tsx | 37 ++ .../modules/ags/widget/elements/Audio.tsx | 15 + .../modules/ags/widget/elements/Battery.tsx | 14 + .../modules/ags/widget/elements/Media.tsx | 28 ++ .../modules/ags/widget/elements/SysTray.tsx | 18 + .../modules/ags/widget/elements/Time.tsx | 12 + .../modules/ags/widget/elements/Wifi.tsx | 17 + .../ags/widget/elements/Workspaces.tsx | 21 + home-manager/patterns/hyprland.nix | 1 - home-manager/patterns/waybar.nix | 455 ------------------ home-manager/users/chest/home.nix | 1 - home-manager/users/chest/modules/waybar.nix | 9 - home-manager/users/sweetbread/home.nix | 1 - .../users/sweetbread/modules/waybar.nix | 9 - 21 files changed, 357 insertions(+), 1214 deletions(-) create mode 100644 home-manager/modules/ags/app.ts delete mode 100644 home-manager/modules/ags/config.js create mode 100644 home-manager/modules/ags/style.scss create mode 100644 home-manager/modules/ags/widget/Bar.tsx create mode 100644 home-manager/modules/ags/widget/elements/Audio.tsx create mode 100644 home-manager/modules/ags/widget/elements/Battery.tsx create mode 100644 home-manager/modules/ags/widget/elements/Media.tsx create mode 100644 home-manager/modules/ags/widget/elements/SysTray.tsx create mode 100644 home-manager/modules/ags/widget/elements/Time.tsx create mode 100644 home-manager/modules/ags/widget/elements/Wifi.tsx create mode 100644 home-manager/modules/ags/widget/elements/Workspaces.tsx delete mode 100644 home-manager/patterns/waybar.nix delete mode 100644 home-manager/users/chest/modules/waybar.nix delete mode 100644 home-manager/users/sweetbread/modules/waybar.nix diff --git a/flake.lock b/flake.lock index f94c03f..82b8c06 100644 --- a/flake.lock +++ b/flake.lock @@ -25,11 +25,11 @@ "nixpkgs": "nixpkgs_2" }, "locked": { - "lastModified": 1735172916, - "narHash": "sha256-gaX0dray5HOMygc/MtYJHQCqh6ZBkLsy1A2vVibFLZg=", + "lastModified": 1735346534, + "narHash": "sha256-geDO7T1mbCr9dhc7JWPor+zsCBMwbJL2ADq9I3r+B9g=", "owner": "Aylur", "repo": "ags", - "rev": "46aad56c4eb33cd83cd32b4757b96731bebc81a7", + "rev": "bb963edccb61be0f40cb8767ab2bf45324fff3f3", "type": "github" }, "original": { @@ -38,25 +38,6 @@ "type": "github" } }, - "ags_2": { - "inputs": { - "astal": "astal_2", - "nixpkgs": "nixpkgs_5" - }, - "locked": { - "lastModified": 1734091628, - "narHash": "sha256-8O3i8zESjHVsGzyXb8gEpLztvANq3Ot5bwo60YKJc7k=", - "owner": "aylur", - "repo": "ags", - "rev": "27cd93147aba09142fa585fd16f13c56268b696c", - "type": "github" - }, - "original": { - "owner": "aylur", - "repo": "ags", - "type": "github" - } - }, "aquamarine": { "inputs": { "hyprutils": [ @@ -98,51 +79,11 @@ ] }, "locked": { - "lastModified": 1733520119, - "narHash": "sha256-6K07ZJTnFu1xASBCMtVc9cFTbBEauwSc7gGBmjLkLSk=", + "lastModified": 1735172721, + "narHash": "sha256-rtEAwGsHSppnkR3Qg3eRJ6Xh/F84IY9CrBBLzYabalY=", "owner": "aylur", "repo": "astal", - "rev": "4c19d8d06fa25cc6389f37abe8839b4d8be5c0d6", - "type": "github" - }, - "original": { - "owner": "aylur", - "repo": "astal", - "type": "github" - } - }, - "astal_2": { - "inputs": { - "nixpkgs": [ - "hyprpanel", - "ags", - "nixpkgs" - ] - }, - "locked": { - "lastModified": 1733520119, - "narHash": "sha256-6K07ZJTnFu1xASBCMtVc9cFTbBEauwSc7gGBmjLkLSk=", - "owner": "aylur", - "repo": "astal", - "rev": "4c19d8d06fa25cc6389f37abe8839b4d8be5c0d6", - "type": "github" - }, - "original": { - "owner": "aylur", - "repo": "astal", - "type": "github" - } - }, - "astal_3": { - "inputs": { - "nixpkgs": "nixpkgs_6" - }, - "locked": { - "lastModified": 1734814417, - "narHash": "sha256-R+tLGIxlaqsOmV52TdXHP0u33q5PdJ77gtiUPK5BbMg=", - "owner": "aylur", - "repo": "astal", - "rev": "3468763d51d389c67ec7b1a390ffa8a5328bddb6", + "rev": "6c84b64efc736e039a8a10774a4a1bf772c37aa2", "type": "github" }, "original": { @@ -619,26 +560,6 @@ "type": "github" } }, - "hyprpanel": { - "inputs": { - "ags": "ags_2", - "astal": "astal_3", - "nixpkgs": "nixpkgs_7" - }, - "locked": { - "lastModified": 1735207839, - "narHash": "sha256-4PlQB9nan29e5Kl0U9Eyl5mKz8GmR1NEChBmfBhWOp0=", - "owner": "Jas-SinghFSU", - "repo": "HyprPanel", - "rev": "0c9b72708e02388c35e1524929982412165189c7", - "type": "github" - }, - "original": { - "owner": "Jas-SinghFSU", - "repo": "HyprPanel", - "type": "github" - } - }, "hyprutils": { "inputs": { "nixpkgs": [ @@ -749,45 +670,13 @@ "type": "github" } }, - "nixpkgs_10": { - "locked": { - "lastModified": 1732238832, - "narHash": "sha256-sQxuJm8rHY20xq6Ah+GwIUkF95tWjGRd1X8xF+Pkk38=", - "owner": "NixOS", - "repo": "nixpkgs", - "rev": "8edf06bea5bcbee082df1b7369ff973b91618b8d", - "type": "github" - }, - "original": { - "owner": "NixOS", - "ref": "nixpkgs-unstable", - "repo": "nixpkgs", - "type": "github" - } - }, - "nixpkgs_11": { - "locked": { - "lastModified": 1715534503, - "narHash": "sha256-5ZSVkFadZbFP1THataCaSf0JH2cAH3S29hU9rrxTEqk=", - "owner": "nixos", - "repo": "nixpkgs", - "rev": "2057814051972fa1453ddfb0d98badbea9b83c06", - "type": "github" - }, - "original": { - "owner": "nixos", - "ref": "nixos-unstable", - "repo": "nixpkgs", - "type": "github" - } - }, "nixpkgs_2": { "locked": { - "lastModified": 1733581040, - "narHash": "sha256-Qn3nPMSopRQJgmvHzVqPcE3I03zJyl8cSbgnnltfFDY=", + "lastModified": 1734649271, + "narHash": "sha256-4EVBRhOjMDuGtMaofAIqzJbg4Ql7Ai0PSeuVZTHjyKQ=", "owner": "nixos", "repo": "nixpkgs", - "rev": "22c3f2cf41a0e70184334a958e6b124fb0ce3e01", + "rev": "d70bd19e0a38ad4790d3913bf08fcbfc9eeca507", "type": "github" }, "original": { @@ -831,11 +720,11 @@ }, "nixpkgs_5": { "locked": { - "lastModified": 1733581040, - "narHash": "sha256-Qn3nPMSopRQJgmvHzVqPcE3I03zJyl8cSbgnnltfFDY=", + "lastModified": 1734649271, + "narHash": "sha256-4EVBRhOjMDuGtMaofAIqzJbg4Ql7Ai0PSeuVZTHjyKQ=", "owner": "nixos", "repo": "nixpkgs", - "rev": "22c3f2cf41a0e70184334a958e6b124fb0ce3e01", + "rev": "d70bd19e0a38ad4790d3913bf08fcbfc9eeca507", "type": "github" }, "original": { @@ -846,54 +735,6 @@ } }, "nixpkgs_6": { - "locked": { - "lastModified": 1734424634, - "narHash": "sha256-cHar1vqHOOyC7f1+tVycPoWTfKIaqkoe1Q6TnKzuti4=", - "owner": "nixos", - "repo": "nixpkgs", - "rev": "d3c42f187194c26d9f0309a8ecc469d6c878ce33", - "type": "github" - }, - "original": { - "owner": "nixos", - "ref": "nixos-unstable", - "repo": "nixpkgs", - "type": "github" - } - }, - "nixpkgs_7": { - "locked": { - "lastModified": 1734649271, - "narHash": "sha256-4EVBRhOjMDuGtMaofAIqzJbg4Ql7Ai0PSeuVZTHjyKQ=", - "owner": "nixos", - "repo": "nixpkgs", - "rev": "d70bd19e0a38ad4790d3913bf08fcbfc9eeca507", - "type": "github" - }, - "original": { - "owner": "nixos", - "ref": "nixos-unstable", - "repo": "nixpkgs", - "type": "github" - } - }, - "nixpkgs_8": { - "locked": { - "lastModified": 1734649271, - "narHash": "sha256-4EVBRhOjMDuGtMaofAIqzJbg4Ql7Ai0PSeuVZTHjyKQ=", - "owner": "nixos", - "repo": "nixpkgs", - "rev": "d70bd19e0a38ad4790d3913bf08fcbfc9eeca507", - "type": "github" - }, - "original": { - "owner": "nixos", - "ref": "nixos-unstable", - "repo": "nixpkgs", - "type": "github" - } - }, - "nixpkgs_9": { "locked": { "lastModified": 1731763621, "narHash": "sha256-ddcX4lQL0X05AYkrkV2LMFgGdRvgap7Ho8kgon3iWZk=", @@ -909,6 +750,38 @@ "type": "github" } }, + "nixpkgs_7": { + "locked": { + "lastModified": 1732238832, + "narHash": "sha256-sQxuJm8rHY20xq6Ah+GwIUkF95tWjGRd1X8xF+Pkk38=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "8edf06bea5bcbee082df1b7369ff973b91618b8d", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixpkgs-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixpkgs_8": { + "locked": { + "lastModified": 1715534503, + "narHash": "sha256-5ZSVkFadZbFP1THataCaSf0JH2cAH3S29hU9rrxTEqk=", + "owner": "nixos", + "repo": "nixpkgs", + "rev": "2057814051972fa1453ddfb0d98badbea9b83c06", + "type": "github" + }, + "original": { + "owner": "nixos", + "ref": "nixos-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, "pre-commit-hooks": { "inputs": { "flake-compat": "flake-compat_2", @@ -941,8 +814,7 @@ "home-manager": "home-manager", "hyprland": "hyprland", "hyprland-plugins": "hyprland-plugins", - "hyprpanel": "hyprpanel", - "nixpkgs": "nixpkgs_8", + "nixpkgs": "nixpkgs_5", "nixpkgs-stable": "nixpkgs-stable_2", "sops-nix": "sops-nix", "stylix": "stylix", @@ -951,7 +823,7 @@ }, "sops-nix": { "inputs": { - "nixpkgs": "nixpkgs_9" + "nixpkgs": "nixpkgs_6" }, "locked": { "lastModified": 1734546875, @@ -977,7 +849,7 @@ "flake-utils": "flake-utils", "gnome-shell": "gnome-shell", "home-manager": "home-manager_2", - "nixpkgs": "nixpkgs_10", + "nixpkgs": "nixpkgs_7", "systems": "systems_2", "tinted-foot": "tinted-foot", "tinted-kitty": "tinted-kitty", @@ -1080,7 +952,7 @@ "tlock": { "inputs": { "flake-parts": "flake-parts", - "nixpkgs": "nixpkgs_11" + "nixpkgs": "nixpkgs_8" }, "locked": { "lastModified": 1716429453, diff --git a/flake.nix b/flake.nix index 4d9257d..fcc30da 100644 --- a/flake.nix +++ b/flake.nix @@ -24,7 +24,6 @@ ayugram-desktop.url = "github:/ayugram-port/ayugram-desktop/release?submodules=1"; tlock.url = "git+https://github.com/eklairs/tlock?submodules=1"; - hyprpanel.url = "github:Jas-SinghFSU/HyprPanel"; hyprland.url = "github:hyprwm/Hyprland"; hyprland-plugins = { url = "github:hyprwm/hyprland-plugins"; @@ -37,13 +36,12 @@ }; }; - outputs = { self, nixpkgs, nixpkgs-stable, home-manager, ... }@inputs: let - system = "x86_64-linux"; - pkgs = import nixpkgs { - inherit system; - overlays = [ inputs.hyprpanel.overlay ]; - }; - in { + outputs = { self, nixpkgs, nixpkgs-stable, home-manager, ... }@inputs: + + let + system = "x86_64-linux"; + in { + nixosConfigurations = { Rias = nixpkgs.lib.nixosSystem { specialArgs = { @@ -90,7 +88,7 @@ homeConfigurations = { sweetbread = home-manager.lib.homeManagerConfiguration { - inherit pkgs; + pkgs = nixpkgs.legacyPackages.${system}; extraSpecialArgs = { inherit inputs; pkgs-stable = import nixpkgs-stable { @@ -102,12 +100,11 @@ ./home-manager/users/sweetbread/home.nix inputs.sops-nix.homeManagerModules.sops inputs.stylix.homeManagerModules.stylix - inputs.ags.homeManagerModules.default ]; }; chest = home-manager.lib.homeManagerConfiguration { - inherit pkgs; + pkgs = nixpkgs.legacyPackages.${system}; extraSpecialArgs = { inherit inputs; pkgs-stable = import nixpkgs-stable { @@ -119,7 +116,6 @@ ./home-manager/users/chest/home.nix inputs.sops-nix.homeManagerModules.sops inputs.stylix.homeManagerModules.stylix - inputs.ags.homeManagerModules.default ]; }; }; diff --git a/home-manager/modules/ags.nix b/home-manager/modules/ags.nix index 471574d..62c4503 100644 --- a/home-manager/modules/ags.nix +++ b/home-manager/modules/ags.nix @@ -1,325 +1,20 @@ -{ inputs, pkgs, config, ... }: { - # imports = [ inputs.ags.homeManagerModules.default ]; +{ inputs, pkgs, ... }: { + imports = [ inputs.ags.homeManagerModules.default ]; programs.ags = { enable = true; - # null or path, leave as null if you don't want hm to manage the config - configDir = null; + configDir = ./ags; - # additional packages to add to gjs's runtime - extraPackages = with pkgs; [ - gtksourceview - webkitgtk - accountsservice + extraPackages = with inputs.ags.packages.${pkgs.system}; [ + battery + mpris + hyprland + network + tray + wireplumber ]; }; - xdg.configFile."ags/config.js".text = /*js*/ '' -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."'], -}) - -// widgets can be only assigned as a child in one container -// so to make a reuseable widget, make it a function -// then you can simply instantiate one by calling it - -function Workspaces() { - const activeId = hyprland.active.workspace.bind("id") - const workspaces = hyprland.bind("workspaces") - .as(ws => ws.map(({ id }) => Widget.Button({ - on_clicked: () => hyprland.messageAsync(`dispatch workspace ''${id}`), - child: Widget.Label(`''${id}`), - class_name: activeId.as(i => `''${i === id ? "focused" : ""}`), - }))) - - return Widget.Box({ - class_name: "workspaces", - children: workspaces, - }) -} - - -function ClientTitle() { - return Widget.Label({ - class_name: "client-title", - label: hyprland.active.client.bind("title"), - }) -} - - -function Clock() { - return Widget.Label({ - class_name: "clock", - label: date.bind(), - }) -} - - -// we don't need dunst or any other notification daemon -// because the Notifications module is a notification daemon itself -function Notification() { - const popups = notifications.bind("popups") - return Widget.Box({ - class_name: "notification", - visible: popups.as(p => p.length > 0), - children: [ - Widget.Icon({ - icon: "preferences-system-notifications-symbolic", - }), - Widget.Label({ - label: popups.as(p => p[0]?.summary || ""), - }), - ], - }) -} - - -function Media() { - const label = Utils.watch("default", mpris, "player-changed", () => { - if (mpris.players[0]) { - const { track_artists, track_title } = mpris.players[0] - return `''${track_artists.join(", ")} - ''${track_title}` - } else { - return "Nothing is playing" - } - }) - - print(Object.values(label)) - if (label != "default") { - return Widget.Button({ - class_name: "media", - on_primary_click: () => mpris.getPlayer("")?.playPause(), - on_scroll_up: () => mpris.getPlayer("")?.next(), - on_scroll_down: () => mpris.getPlayer("")?.previous(), - child: Widget.Label({ label }), - }) - } -} - - -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, - 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], - }) -} - - -function BatteryLabel() { - const value = battery.bind("percent").as(p => p > 0 ? p / 100 : 0) - const icon = battery.bind("percent").as(p => - `battery-level-''${Math.floor(p / 10) * 10}-symbolic`) - - return Widget.Box({ - class_name: "battery", - visible: battery.bind("available"), - children: [ - Widget.Icon({ icon }), - Widget.LevelBar({ - widthRequest: 140, - vpack: "center", - value, - }), - ], - }) -} - - -function SysTray() { - const items = systemtray.bind("items") - .as(items => items.map(item => Widget.Button({ - 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({ - children: items, - }) -} - - -// layout of the bar -function Left() { - return Widget.Box({ - spacing: 8, - children: [ - Workspaces(), - ClientTitle(), - ], - }) -} - -function Center() { - return Widget.Box({ - spacing: 8, - children: [ - Media(), - Notification(), - ], - }) -} - -function Right() { - return Widget.Box({ - hpack: "end", - spacing: 8, - children: [ - Volume(), - BatteryLabel(), - Clock(), - SysTray(), - ], - }) -} - -function Bar(monitor = 0) { - return Widget.Window({ - name: `bar-''${monitor}`, // name has to be unique - class_name: "bar", - monitor, - anchor: ["top", "left", "right"], - exclusivity: "exclusive", - child: Widget.CenterBox({ - start_widget: Left(), - center_widget: Center(), - end_widget: Right(), - }), - }) -} - -App.config({ - style: "./style.css", - windows: [ - Bar(), - - // you can call it, for each monitor - // Bar(0), - // Bar(1) - ], -}) - -export { } -''; - - xdg.configFile."ags/style.css".text = let - colors = config.lib.stylix.colors; - - color = { - base = colors.base00; - mantle = colors.base01; - surface0 = colors.base02; - surface1 = colors.base03; - surface2 = colors.base04; - text = colors.base05; - rosewater = colors.base06; - lavander = colors.base07; - red = colors.base08; - peach = colors.base09; - yellow = colors.base0A; - green = colors.base0B; - teal = colors.base0C; - blue = colors.base0D; - mauve = colors.base0E; - flamingo = colors.base0F; - }; -in /*css*/ '' -* { - border: none; - box-shadow: none; - text-shadow: none; -} - -window.bar { - background-color: transparent; - color: #${color.text}; -} - -button { - /* size: 20px; */ - background-color: transparent; - border-radius: 10px; -} - -button:active { - background-color: /*#${color.surface0}*/ red; -} - -label { - font-weight: bold; -} - -.workspaces { - background-color: #${color.base}; - border-radius: 10px; -} - -.workspaces button { - color: #${color.surface2}; - background: transparent; - padding: 5px; -} - -.workspaces button:hover { - color: #${color.text}; -} - -.workspaces button.focused { - background-color: #${color.surface0}; - color: #${color.text}; -} - -.client-title { - color: @theme_selected_bg_color; -} - -.notification { - color: yellow; -} - -levelbar block, -highlight { - min-height: 10px; -} -''; - - # home.packages = [ pkgs.ags ]; + wayland.windowManager.hyprland.settings.exec-once = [ "ags run" ]; } diff --git a/home-manager/modules/ags/README.md b/home-manager/modules/ags/README.md index 054a467..f92b20e 100644 --- a/home-manager/modules/ags/README.md +++ b/home-manager/modules/ags/README.md @@ -1,18 +1,12 @@ -# Simple Bar +# Simple Bar Example -setup +![simple-bar](https://github.com/user-attachments/assets/a306c864-56b7-44c4-8820-81f424f32b9b) -```bash -mkdir -p ~/.config/ags -git clone https://github.com/Aylur/ags.git /tmp/ags -cp -r /tmp/ags/example/simple-bar/* ~/.config/ags +A simple bar for Hyprland using -# optionally setup types -ags --init -c ~/.config/ags/config.js -``` - -running - -```bash -ags -c ~/.config/ags/config.js & -``` +- [Battery library](https://aylur.github.io/astal/guide/libraries/battery). +- [Hyprland library](https://aylur.github.io/astal/guide/libraries/hyprland). +- [Mpris library](https://aylur.github.io/astal/guide/libraries/mpris). +- [Network library](https://aylur.github.io/astal/guide/libraries/network). +- [Tray library](https://aylur.github.io/astal/guide/libraries/tray). +- [WirePlumber library](https://aylur.github.io/astal/guide/libraries/wireplumber). diff --git a/home-manager/modules/ags/app.ts b/home-manager/modules/ags/app.ts new file mode 100644 index 0000000..4b7ea48 --- /dev/null +++ b/home-manager/modules/ags/app.ts @@ -0,0 +1,13 @@ +import { App } from "astal/gtk3" +import style from "./style.scss" +import Bar from "./widget/Bar" + +App.start({ + css: style, + instanceName: "js", + requestHandler(request, res) { + print(request) + res("ok") + }, + main: () => App.get_monitors().map(Bar), +}) diff --git a/home-manager/modules/ags/config.js b/home-manager/modules/ags/config.js deleted file mode 100644 index 4c0a30b..0000000 --- a/home-manager/modules/ags/config.js +++ /dev/null @@ -1,219 +0,0 @@ -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."'], -}) - -// widgets can be only assigned as a child in one container -// so to make a reuseable widget, make it a function -// then you can simply instantiate one by calling it - -function Workspaces() { - const activeId = hyprland.active.workspace.bind("id") - const workspaces = hyprland.bind("workspaces") - .as(ws => ws.map(({ id }) => Widget.Button({ - on_clicked: () => hyprland.messageAsync(`dispatch workspace ${id}`), - child: Widget.Label(`${id}`), - class_name: activeId.as(i => `${i === id ? "focused" : ""}`), - }))) - - return Widget.Box({ - class_name: "workspaces", - children: workspaces, - }) -} - - -function ClientTitle() { - return Widget.Label({ - class_name: "client-title", - label: hyprland.active.client.bind("title"), - }) -} - - -function Clock() { - return Widget.Label({ - class_name: "clock", - label: date.bind(), - }) -} - - -// we don't need dunst or any other notification daemon -// because the Notifications module is a notification daemon itself -function Notification() { - const popups = notifications.bind("popups") - return Widget.Box({ - class_name: "notification", - visible: popups.as(p => p.length > 0), - children: [ - Widget.Icon({ - icon: "preferences-system-notifications-symbolic", - }), - Widget.Label({ - label: popups.as(p => p[0]?.summary || ""), - }), - ], - }) -} - - -function Media() { - const label = Utils.watch("", mpris, "player-changed", () => { - if (mpris.players[0]) { - const { track_artists, track_title } = mpris.players[0] - return `${track_artists.join(", ")} - ${track_title}` - } else { - return "Nothing is playing" - } - }) - - return Widget.Button({ - class_name: "media", - on_primary_click: () => mpris.getPlayer("")?.playPause(), - on_scroll_up: () => mpris.getPlayer("")?.next(), - on_scroll_down: () => mpris.getPlayer("")?.previous(), - child: Widget.Label({ label }), - }) -} - - -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, - 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], - }) -} - - -function BatteryLabel() { - const value = battery.bind("percent").as(p => p > 0 ? p / 100 : 0) - const icon = battery.bind("percent").as(p => - `battery-level-${Math.floor(p / 10) * 10}-symbolic`) - - return Widget.Box({ - class_name: "battery", - visible: battery.bind("available"), - children: [ - Widget.Icon({ icon }), - Widget.LevelBar({ - widthRequest: 140, - vpack: "center", - value, - }), - ], - }) -} - - -function SysTray() { - const items = systemtray.bind("items") - .as(items => items.map(item => Widget.Button({ - 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({ - children: items, - }) -} - - -// layout of the bar -function Left() { - return Widget.Box({ - spacing: 8, - children: [ - Workspaces(), - ClientTitle(), - ], - }) -} - -function Center() { - return Widget.Box({ - spacing: 8, - children: [ - Media(), - Notification(), - ], - }) -} - -function Right() { - return Widget.Box({ - hpack: "end", - spacing: 8, - children: [ - Volume(), - BatteryLabel(), - Clock(), - SysTray(), - ], - }) -} - -function Bar(monitor = 0) { - return Widget.Window({ - name: `bar-${monitor}`, // name has to be unique - class_name: "bar", - monitor, - anchor: ["top", "left", "right"], - exclusivity: "exclusive", - child: Widget.CenterBox({ - start_widget: Left(), - center_widget: Center(), - end_widget: Right(), - }), - }) -} - -App.config({ - style: "./style.css", - windows: [ - Bar(), - - // you can call it, for each monitor - // Bar(0), - // Bar(1) - ], -}) - -export { } diff --git a/home-manager/modules/ags/style.scss b/home-manager/modules/ags/style.scss new file mode 100644 index 0000000..f5f771a --- /dev/null +++ b/home-manager/modules/ags/style.scss @@ -0,0 +1,106 @@ +@use "sass:color"; + +$bg: #212223; +$fg: #f1f1f1; +$accent: #378DF7; +$radius: 7px; + +window.Bar { + border: none; + box-shadow: none; + background-color: $bg; + color: $fg; + font-size: 1.1em; + font-weight: bold; + + label { + margin: 0 8px; + } + + .Workspaces { + button { + all: unset; + background-color: transparent; + + &:hover label { + background-color: color.adjust($fg, $alpha: -0.84); + border-color: color.adjust($accent, $alpha: -0.8); + } + + &:active label { + background-color: color.adjust($fg, $alpha: -0.8) + } + } + + label { + transition: 200ms; + padding: 0 8px; + margin: 2px; + border-radius: $radius; + border: 1pt solid transparent; + } + + .focused label { + color: $accent; + border-color: $accent; + } + } + + .SysTray { + margin-right: 8px; + + button { + padding: 0 4px; + } + } + + .FocusedClient { + color: $accent; + } + + .Media .Cover { + min-height: 1.2em; + min-width: 1.2em; + border-radius: $radius; + background-position: center; + background-size: contain; + } + + .Battery label { + padding-left: 0; + margin-left: 0; + } + + .AudioSlider { + * { + all: unset; + } + + icon { + margin-right: .6em; + } + + & { + margin: 0 1em; + } + + trough { + background-color: color.adjust($fg, $alpha: -0.8); + border-radius: $radius; + } + + highlight { + background-color: $accent; + min-height: .8em; + border-radius: $radius; + } + + slider { + background-color: $fg; + border-radius: $radius; + min-height: 1em; + min-width: 1em; + margin: -.2em; + } + } +} diff --git a/home-manager/modules/ags/widget/Bar.tsx b/home-manager/modules/ags/widget/Bar.tsx new file mode 100644 index 0000000..e2b580d --- /dev/null +++ b/home-manager/modules/ags/widget/Bar.tsx @@ -0,0 +1,37 @@ +import { App } from "astal/gtk3" +import { Astal, Gtk, Gdk } from "astal/gtk3" + +import Time from "./elements/Time" +import Wifi from "./elements/Wifi" +import Audio from "./elements/Audio" +import Media from "./elements/Media" +import SysTray from "./elements/SysTray" +import Workspaces from "./elements/Workspaces" +import BatteryLevel from "./elements/Battery" + + +export default function Bar(monitor: Gdk.Monitor) { + const { TOP, LEFT, RIGHT } = Astal.WindowAnchor + + return + + + + + + + + + + + + + +} diff --git a/home-manager/modules/ags/widget/elements/Audio.tsx b/home-manager/modules/ags/widget/elements/Audio.tsx new file mode 100644 index 0000000..95462b3 --- /dev/null +++ b/home-manager/modules/ags/widget/elements/Audio.tsx @@ -0,0 +1,15 @@ +import { bind } from "astal" +import Wp from "gi://AstalWp" + +export default function Audio() { + const speaker = Wp.get_default()?.audio.defaultSpeaker! + + return + + speaker.volume = value} + value={bind(speaker, "volume")} + /> + +} diff --git a/home-manager/modules/ags/widget/elements/Battery.tsx b/home-manager/modules/ags/widget/elements/Battery.tsx new file mode 100644 index 0000000..6dc6934 --- /dev/null +++ b/home-manager/modules/ags/widget/elements/Battery.tsx @@ -0,0 +1,14 @@ +import { bind } from "astal" +import Battery from "gi://AstalBattery" + +export default function BatteryLevel() { + const bat = Battery.get_default() + + return + + +} diff --git a/home-manager/modules/ags/widget/elements/Media.tsx b/home-manager/modules/ags/widget/elements/Media.tsx new file mode 100644 index 0000000..6425b87 --- /dev/null +++ b/home-manager/modules/ags/widget/elements/Media.tsx @@ -0,0 +1,28 @@ +import { bind } from "astal" +import { Gtk } from "astal/gtk3" +import Mpris from "gi://AstalMpris" + +export default function Media() { + const mpris = Mpris.get_default() + + return + {bind(mpris, "players").as(ps => ps[0] ? ( + + + `background-image: url('${cover}');` + )} + /> + + ) : ( + "Nothing Playing" + ))} + +} diff --git a/home-manager/modules/ags/widget/elements/SysTray.tsx b/home-manager/modules/ags/widget/elements/SysTray.tsx new file mode 100644 index 0000000..d938ece --- /dev/null +++ b/home-manager/modules/ags/widget/elements/SysTray.tsx @@ -0,0 +1,18 @@ +import { bind } from "astal" +import Tray from "gi://AstalTray" + +export default function SysTray() { + const tray = Tray.get_default() + + return + {bind(tray, "items").as(items => items.map(item => ( + ["dbusmenu", ag])} + menuModel={bind(item, "menu-model")}> + + + )))} + +} diff --git a/home-manager/modules/ags/widget/elements/Time.tsx b/home-manager/modules/ags/widget/elements/Time.tsx new file mode 100644 index 0000000..a85c079 --- /dev/null +++ b/home-manager/modules/ags/widget/elements/Time.tsx @@ -0,0 +1,12 @@ +import { Variable, GLib } from "astal" + +export default function Time({ format = "%H:%M - %A %e." }) { + const time = Variable("").poll(1000, () => + GLib.DateTime.new_now_local().format(format)!) + + return