From 07a60e91d2607cb4bbde7db60adeda727b064495 Mon Sep 17 00:00:00 2001 From: Hadi <112569860+anotherhadi@users.noreply.github.com> Date: Mon, 28 Sep 2026 20:18:12 +0200 Subject: [PATCH] rework: more TUIs! (#62) Signed-off-by: Hadi <112569860+anotherhadi@users.noreply.github.com> --- flake.lock | 129 ++++- flake.nix | 15 +- .../gui/helium/bookmarks/default.nix | 0 .../gui/helium/bookmarks/entertainment.nix | 0 .../gui/helium/bookmarks/general.nix | 0 .../gui/helium/bookmarks/infosec.nix | 8 - .../gui/helium/bookmarks/jack.nix | 12 - .../gui/helium/bookmarks/other.nix | 6 +- .../gui/helium/bookmarks/tools.nix | 0 home/{programs => }/gui/helium/default.nix | 0 home/{programs => }/gui/helium/system.nix | 0 .../gui/pkgs.nix => gui/pkgs/default.nix} | 0 home/{programs/tui => }/nvf/default.nix | 0 home/{programs/tui => }/nvf/flake.lock | 0 home/{programs/tui => }/nvf/flake.nix | 0 home/{programs/tui => }/nvf/keymaps.nix | 0 home/{programs/tui => }/nvf/languages.nix | 0 home/{programs/tui => }/nvf/mini.nix | 0 home/{programs/tui => }/nvf/options.nix | 0 home/{programs/tui => }/nvf/picker.nix | 0 home/{programs/tui => }/nvf/snacks.nix | 0 home/{programs/tui => }/nvf/utils.nix | 0 home/programs/gui/proton/default.nix | 36 -- home/programs/tui/git/default.nix | 52 -- home/programs/tui/wikiman/default.nix | 49 -- home/system/clipboard/default.nix | 15 +- home/system/hypridle/default.nix | 34 +- home/system/hyprland/bindings.nix | 69 +-- home/system/hyprland/default.nix | 1 + home/system/hyprland/scripts.nix | 61 +++ home/system/hyprlock/default.nix | 9 + home/system/mime/default.nix | 15 +- home/system/power/default.nix | 42 ++ home/system/scripts/default.nix | 16 + home/system/swaync/default.nix | 30 +- home/system/termfilechooser/default.nix | 8 +- home/system/tofi/default.nix | 2 +- home/system/tofi/desktop-actions.nix | 75 +-- home/system/tofi/scripts.nix | 35 ++ home/system/udiskie/default.nix | 2 +- home/system/waybar/battery-monitor.sh | 103 ---- home/system/waybar/default.nix | 46 +- home/system/waybar/scripts.nix | 456 ------------------ home/system/waybar/scripts/audio.nix | 74 +++ home/system/waybar/scripts/bluetooth.nix | 50 ++ home/system/waybar/scripts/brightness.nix | 32 ++ home/system/waybar/scripts/default.nix | 11 + home/system/waybar/scripts/devices.nix | 63 +++ home/system/waybar/scripts/misc.nix | 65 +++ home/system/waybar/scripts/network.nix | 77 +++ home/system/waybar/scripts/osd.nix | 27 ++ home/system/waybar/settings.nix | 21 +- home/{programs => }/tui/elio/default.nix | 14 +- home/{programs => }/tui/ghostty/default.nix | 0 home/tui/git/default.nix | 64 +++ home/{programs => }/tui/git/lazygit.nix | 0 home/{programs => }/tui/git/signing.nix | 2 +- home/{programs => }/tui/ilovetui/default.nix | 0 home/tui/kew/default.nix | 45 ++ home/tui/misc/btop/default.nix | 21 + home/tui/misc/cava/default.nix | 5 + .../misc/cybersecurity/default.nix} | 9 +- .../misc/cybersecurity/pkgs.nix} | 0 home/tui/misc/default.nix | 6 + .../dev.nix => tui/misc/dev/default.nix} | 0 home/tui/misc/eilmeldung/default.nix | 25 + home/tui/misc/monitui/default.nix | 15 + .../tui => tui/misc}/navi/default.nix | 0 .../tui => tui/misc}/nix-utils/default.nix | 0 home/tui/misc/usbguard-tui/default.nix | 15 + home/{programs => }/tui/nixy/default.nix | 0 home/{programs => }/tui/nixy/flake.nix | 0 home/{programs => }/tui/nixy/package.nix | 0 .../tui/pkgs.nix => tui/pkgs/default.nix} | 20 +- home/tui/proton/default.nix | 8 + home/tui/proton/proton-auth.nix | 26 + home/tui/proton/proton-vpn.nix | 7 + home/{programs => }/tui/shell/default.nix | 0 home/{programs => }/tui/shell/direnv.nix | 0 home/{programs => }/tui/shell/eza.nix | 0 home/{programs => }/tui/shell/fzf.nix | 5 + home/{programs => }/tui/shell/starship.nix | 0 home/{programs => }/tui/shell/zoxide.nix | 0 home/{programs => }/tui/shell/zsh.nix | 33 +- .../tui/myx => tui/spotify}/default.nix | 10 +- home/tui/tldr/default.nix | 26 + hosts/laptop/configuration.nix | 72 ++- hosts/laptop/flake.nix | 1 + hosts/laptop/home.nix | 56 +-- hosts/laptop/persistence.nix | 29 -- hosts/laptop/secrets/secrets.yaml | 6 +- hosts/laptop/usbguard.nix | 31 -- hosts/server/home.nix | 2 +- hosts/work/home.nix | 2 +- nixos/lanzaboot.nix | 55 +++ nixos/tuigreet.nix | 6 +- nixos/utils.nix | 7 +- nixos/vulnix.nix | 4 + 98 files changed, 1280 insertions(+), 1093 deletions(-) rename home/{programs => }/gui/helium/bookmarks/default.nix (100%) rename home/{programs => }/gui/helium/bookmarks/entertainment.nix (100%) rename home/{programs => }/gui/helium/bookmarks/general.nix (100%) rename home/{programs => }/gui/helium/bookmarks/infosec.nix (83%) rename home/{programs => }/gui/helium/bookmarks/jack.nix (84%) rename home/{programs => }/gui/helium/bookmarks/other.nix (79%) rename home/{programs => }/gui/helium/bookmarks/tools.nix (100%) rename home/{programs => }/gui/helium/default.nix (100%) rename home/{programs => }/gui/helium/system.nix (100%) rename home/{programs/gui/pkgs.nix => gui/pkgs/default.nix} (100%) rename home/{programs/tui => }/nvf/default.nix (100%) rename home/{programs/tui => }/nvf/flake.lock (100%) rename home/{programs/tui => }/nvf/flake.nix (100%) rename home/{programs/tui => }/nvf/keymaps.nix (100%) rename home/{programs/tui => }/nvf/languages.nix (100%) rename home/{programs/tui => }/nvf/mini.nix (100%) rename home/{programs/tui => }/nvf/options.nix (100%) rename home/{programs/tui => }/nvf/picker.nix (100%) rename home/{programs/tui => }/nvf/snacks.nix (100%) rename home/{programs/tui => }/nvf/utils.nix (100%) delete mode 100644 home/programs/gui/proton/default.nix delete mode 100644 home/programs/tui/git/default.nix delete mode 100644 home/programs/tui/wikiman/default.nix create mode 100644 home/system/hyprland/scripts.nix create mode 100644 home/system/power/default.nix create mode 100644 home/system/scripts/default.nix create mode 100644 home/system/tofi/scripts.nix delete mode 100644 home/system/waybar/battery-monitor.sh delete mode 100644 home/system/waybar/scripts.nix create mode 100644 home/system/waybar/scripts/audio.nix create mode 100644 home/system/waybar/scripts/bluetooth.nix create mode 100644 home/system/waybar/scripts/brightness.nix create mode 100644 home/system/waybar/scripts/default.nix create mode 100644 home/system/waybar/scripts/devices.nix create mode 100644 home/system/waybar/scripts/misc.nix create mode 100644 home/system/waybar/scripts/network.nix create mode 100644 home/system/waybar/scripts/osd.nix rename home/{programs => }/tui/elio/default.nix (92%) rename home/{programs => }/tui/ghostty/default.nix (100%) create mode 100644 home/tui/git/default.nix rename home/{programs => }/tui/git/lazygit.nix (100%) rename home/{programs => }/tui/git/signing.nix (81%) rename home/{programs => }/tui/ilovetui/default.nix (100%) create mode 100644 home/tui/kew/default.nix create mode 100644 home/tui/misc/btop/default.nix create mode 100644 home/tui/misc/cava/default.nix rename home/{programs/group/cybersecurity.nix => tui/misc/cybersecurity/default.nix} (86%) rename home/{programs/group/cybersecurity-packages.nix => tui/misc/cybersecurity/pkgs.nix} (100%) create mode 100644 home/tui/misc/default.nix rename home/{programs/group/dev.nix => tui/misc/dev/default.nix} (100%) create mode 100644 home/tui/misc/eilmeldung/default.nix create mode 100644 home/tui/misc/monitui/default.nix rename home/{programs/tui => tui/misc}/navi/default.nix (100%) rename home/{programs/tui => tui/misc}/nix-utils/default.nix (100%) create mode 100644 home/tui/misc/usbguard-tui/default.nix rename home/{programs => }/tui/nixy/default.nix (100%) rename home/{programs => }/tui/nixy/flake.nix (100%) rename home/{programs => }/tui/nixy/package.nix (100%) rename home/{programs/tui/pkgs.nix => tui/pkgs/default.nix} (67%) create mode 100644 home/tui/proton/default.nix create mode 100644 home/tui/proton/proton-auth.nix create mode 100644 home/tui/proton/proton-vpn.nix rename home/{programs => }/tui/shell/default.nix (100%) rename home/{programs => }/tui/shell/direnv.nix (100%) rename home/{programs => }/tui/shell/eza.nix (100%) rename home/{programs => }/tui/shell/fzf.nix (90%) rename home/{programs => }/tui/shell/starship.nix (100%) rename home/{programs => }/tui/shell/zoxide.nix (100%) rename home/{programs => }/tui/shell/zsh.nix (78%) rename home/{programs/tui/myx => tui/spotify}/default.nix (78%) create mode 100644 home/tui/tldr/default.nix delete mode 100644 hosts/laptop/persistence.nix delete mode 100644 hosts/laptop/usbguard.nix create mode 100644 nixos/lanzaboot.nix diff --git a/flake.lock b/flake.lock index 3d1e6aad..d64b2f70 100644 --- a/flake.lock +++ b/flake.lock @@ -93,6 +93,21 @@ "type": "github" } }, + "crane": { + "locked": { + "lastModified": 1789760033, + "narHash": "sha256-jtT4yxZpR8seYnlCMMWSSPlFN92zO6ICuZ8pJrmi86k=", + "owner": "ipetkov", + "repo": "crane", + "rev": "73b980519cefc727a5f6cc8e5c0947a2f9be6edd", + "type": "github" + }, + "original": { + "owner": "ipetkov", + "repo": "crane", + "type": "github" + } + }, "default-creds": { "flake": false, "locked": { @@ -181,6 +196,22 @@ } }, "flake-compat_2": { + "flake": false, + "locked": { + "lastModified": 1767039857, + "narHash": "sha256-vNpUSpF5Nuw8xvDLj2KCwwksIbjua2LZCqhV1LNRDns=", + "owner": "NixOS", + "repo": "flake-compat", + "rev": "5edf11c44bc78a0d334f6334cdaf7d60d732daab", + "type": "github" + }, + "original": { + "owner": "NixOS", + "repo": "flake-compat", + "type": "github" + } + }, + "flake-compat_3": { "flake": false, "locked": { "lastModified": 1777699697, @@ -406,6 +437,29 @@ "type": "github" } }, + "lanzaboote": { + "inputs": { + "crane": "crane", + "nixpkgs": [ + "nixpkgs" + ], + "pre-commit": "pre-commit", + "rust-overlay": "rust-overlay" + }, + "locked": { + "lastModified": 1789982869, + "narHash": "sha256-o72O4Y6YZ2q6SkgqU8krWJomtVW7gsTAVt1eAv8bebU=", + "owner": "nix-community", + "repo": "lanzaboote", + "rev": "074c4938b829e745c878872fc165eea3a6b27399", + "type": "github" + }, + "original": { + "owner": "nix-community", + "repo": "lanzaboote", + "type": "github" + } + }, "mnw": { "locked": { "lastModified": 1780772958, @@ -513,11 +567,11 @@ }, "nixpkgs-unstable": { "locked": { - "lastModified": 1787135253, - "narHash": "sha256-RD2kNWCG+Bjo6h+JVjWVNntZs2GtRoeY2xHjts/FNkA=", + "lastModified": 1790046670, + "narHash": "sha256-MYiI+CzL0tuWgRPjGsKCDHqYs2T3OzMlMQWOYWG0qso=", "owner": "nixos", "repo": "nixpkgs", - "rev": "ffb3c9b700e759be2ef13237c9d8f953b32a1e46", + "rev": "6774f7bc253789b113a4f39285dc0fa100abeacc", "type": "github" }, "original": { @@ -649,7 +703,7 @@ }, "nvf": { "inputs": { - "flake-compat": "flake-compat_2", + "flake-compat": "flake-compat_3", "mnw": "mnw", "nixpkgs": "nixpkgs_6" }, @@ -677,15 +731,37 @@ ] }, "locked": { - "path": "./home/programs/tui/nvf", + "path": "./home/nvf", "type": "path" }, "original": { - "path": "./home/programs/tui/nvf", + "path": "./home/nvf", "type": "path" }, "parent": [] }, + "pre-commit": { + "inputs": { + "flake-compat": "flake-compat_2", + "nixpkgs": [ + "lanzaboote", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1789514889, + "narHash": "sha256-PFD1nxptCXJyJoiYO1gf/5Vv43yqGpHtMC6LUhl9/pQ=", + "owner": "cachix", + "repo": "git-hooks.nix", + "rev": "59f4ca0d063a1a3ec722c88b51a33004862e5379", + "type": "github" + }, + "original": { + "owner": "cachix", + "repo": "git-hooks.nix", + "type": "github" + } + }, "root": { "inputs": { "default-creds": "default-creds", @@ -695,6 +771,7 @@ "helium-browser": "helium-browser", "home-manager": "home-manager", "impermanence": "impermanence", + "lanzaboote": "lanzaboote", "nix-index-database": "nix-index-database", "nixarr": "nixarr", "nixos-hardware": "nixos-hardware", @@ -704,7 +781,29 @@ "nvf": "nvf", "nvf-config": "nvf-config", "sops-nix": "sops-nix", - "stylix": "stylix" + "stylix": "stylix", + "tldr-pages-src": "tldr-pages-src" + } + }, + "rust-overlay": { + "inputs": { + "nixpkgs": [ + "lanzaboote", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1789889921, + "narHash": "sha256-aL/ogiN7qZCGeNovS1f9hX73jwYIKb4Pcq6AZm57WtY=", + "owner": "oxalica", + "repo": "rust-overlay", + "rev": "1fb104a12a8667045559b2575d6d448ae2fbd99b", + "type": "github" + }, + "original": { + "owner": "oxalica", + "repo": "rust-overlay", + "type": "github" } }, "sops-nix": { @@ -855,6 +954,22 @@ "type": "github" } }, + "tldr-pages-src": { + "flake": false, + "locked": { + "lastModified": 1789901872, + "narHash": "sha256-UQoJuW4895ocBz/vMPBO7Vdr6X5AgtEurackYF1titY=", + "owner": "tldr-pages", + "repo": "tldr", + "rev": "615ccdb9d0323c13a2387693c8b0de8106042f4a", + "type": "github" + }, + "original": { + "owner": "tldr-pages", + "repo": "tldr", + "type": "github" + } + }, "treefmt-nix": { "inputs": { "nixpkgs": [ diff --git a/flake.nix b/flake.nix index 423f4371..a700d75f 100644 --- a/flake.nix +++ b/flake.nix @@ -1,8 +1,7 @@ { # https://github.com/anotherhadi/nixy description = '' - Nixy simplifies and unifies the Hyprland ecosystem with a modular, easily customizable setup. - It provides a structured way to manage your system configuration and dotfiles with minimal effort. + Nixy simplifies and unifies the Hyprland ecosystem with a minimalist & easily customizable NixOS setup, heavily focused on TUIs. ''; inputs = { @@ -11,7 +10,7 @@ nixos-hardware.url = "github:NixOS/nixos-hardware"; nvf.url = "github:notashelf/nvf"; nvf-config = { - url = "path:./home/programs/tui/nvf"; + url = "path:./home/nvf"; inputs.nixpkgs.follows = "nixpkgs"; inputs.nvf.follows = "nvf"; }; @@ -40,6 +39,10 @@ url = "github:nix-community/disko"; inputs.nixpkgs.follows = "nixpkgs"; }; + lanzaboote = { + url = "github:nix-community/lanzaboote"; + inputs.nixpkgs.follows = "nixpkgs"; + }; helium-browser = { url = "github:oxcl/nix-flake-helium-browser"; inputs.nixpkgs.follows = "nixpkgs-unstable"; @@ -52,6 +55,10 @@ url = "github:anotherhadi/default-creds"; flake = false; }; + tldr-pages-src = { + url = "github:tldr-pages/tldr"; + flake = false; + }; # Server nixarr.url = "github:nix-media-server/nixarr"; @@ -87,7 +94,7 @@ (system: f system (import nixpkgs {inherit system;})); in merge [ - (import ./home/programs/tui/nixy/flake.nix args) + (import ./home/tui/nixy/flake.nix args) { formatter.${system} = pkgs.alejandra; packages.${system}.nvim = inputs.nvf-config.packages.${system}.nvim; diff --git a/home/programs/gui/helium/bookmarks/default.nix b/home/gui/helium/bookmarks/default.nix similarity index 100% rename from home/programs/gui/helium/bookmarks/default.nix rename to home/gui/helium/bookmarks/default.nix diff --git a/home/programs/gui/helium/bookmarks/entertainment.nix b/home/gui/helium/bookmarks/entertainment.nix similarity index 100% rename from home/programs/gui/helium/bookmarks/entertainment.nix rename to home/gui/helium/bookmarks/entertainment.nix diff --git a/home/programs/gui/helium/bookmarks/general.nix b/home/gui/helium/bookmarks/general.nix similarity index 100% rename from home/programs/gui/helium/bookmarks/general.nix rename to home/gui/helium/bookmarks/general.nix diff --git a/home/programs/gui/helium/bookmarks/infosec.nix b/home/gui/helium/bookmarks/infosec.nix similarity index 83% rename from home/programs/gui/helium/bookmarks/infosec.nix rename to home/gui/helium/bookmarks/infosec.nix index 1952da04..8d02c939 100644 --- a/home/programs/gui/helium/bookmarks/infosec.nix +++ b/home/gui/helium/bookmarks/infosec.nix @@ -7,10 +7,6 @@ name = "Nix 4 Cyber"; url = "https://n4c.hadi.icu"; } - { - name = "Infosec Notes - Anotherhadi"; - url = "https://hadi.icu/notes"; - } { name = "Cyberchef"; url = "https://cyberchef.hadi.icu"; @@ -27,10 +23,6 @@ name = "Hack The Box"; url = "https://hackthebox.com"; } - { - name = "Iknowyou"; - url = "https://iknowyou-prod.hadi.icu"; - } { name = "Exploit-DB"; url = "https://exploit-db.com"; diff --git a/home/programs/gui/helium/bookmarks/jack.nix b/home/gui/helium/bookmarks/jack.nix similarity index 84% rename from home/programs/gui/helium/bookmarks/jack.nix rename to home/gui/helium/bookmarks/jack.nix index bdcd5d9d..73c842f9 100644 --- a/home/programs/gui/helium/bookmarks/jack.nix +++ b/home/gui/helium/bookmarks/jack.nix @@ -15,14 +15,6 @@ name = "Gitea"; url = "https://git.hadi.icu"; } - { - name = "Mealie"; - url = "https://mealie.hadi.icu"; - } - { - name = "Wallpapers"; - url = "https://wallpapers.hadi.icu"; - } { name = "Default Creds"; url = "https://default-creds.hadi.icu"; @@ -61,10 +53,6 @@ name = "AdGuard"; url = "https://adguard.hadi.icu"; } - { - name = "Umami"; - url = "https://umami.hadi.icu"; - } { name = "Cloudflare"; url = "https://dash.cloudflare.com"; diff --git a/home/programs/gui/helium/bookmarks/other.nix b/home/gui/helium/bookmarks/other.nix similarity index 79% rename from home/programs/gui/helium/bookmarks/other.nix rename to home/gui/helium/bookmarks/other.nix index 7e651a5f..137335df 100644 --- a/home/programs/gui/helium/bookmarks/other.nix +++ b/home/gui/helium/bookmarks/other.nix @@ -39,11 +39,7 @@ } { name = "Startpage Config"; - url = "https://www.startpage.com/do/mypage.pl?prfe=45d331deb05471d659dba933e7400df51d952bb103da6f6125c0e769a6be1d65610456a479f495ceeee7e97311cf227d7c1bb198de0ceeb193d8cddf9c455c19a409cc35c3e3f542ee27bd7cecd3"; - } - { - name = "Feedly"; - url = "https://feedly.com"; + url = "https://www.startpage.com/do/mypage.pl?prfe=2ca22738c4725515827ee9783be629ea1c26114819ab4a8c32573d96b3fc98540c50f251d1613da751834e14a9f50c7913eb528705c8ea7f067899ddd18e2d18f6f382cada947f7095cb9bead84dbb1aa455"; } { name = "MyNixOS"; diff --git a/home/programs/gui/helium/bookmarks/tools.nix b/home/gui/helium/bookmarks/tools.nix similarity index 100% rename from home/programs/gui/helium/bookmarks/tools.nix rename to home/gui/helium/bookmarks/tools.nix diff --git a/home/programs/gui/helium/default.nix b/home/gui/helium/default.nix similarity index 100% rename from home/programs/gui/helium/default.nix rename to home/gui/helium/default.nix diff --git a/home/programs/gui/helium/system.nix b/home/gui/helium/system.nix similarity index 100% rename from home/programs/gui/helium/system.nix rename to home/gui/helium/system.nix diff --git a/home/programs/gui/pkgs.nix b/home/gui/pkgs/default.nix similarity index 100% rename from home/programs/gui/pkgs.nix rename to home/gui/pkgs/default.nix diff --git a/home/programs/tui/nvf/default.nix b/home/nvf/default.nix similarity index 100% rename from home/programs/tui/nvf/default.nix rename to home/nvf/default.nix diff --git a/home/programs/tui/nvf/flake.lock b/home/nvf/flake.lock similarity index 100% rename from home/programs/tui/nvf/flake.lock rename to home/nvf/flake.lock diff --git a/home/programs/tui/nvf/flake.nix b/home/nvf/flake.nix similarity index 100% rename from home/programs/tui/nvf/flake.nix rename to home/nvf/flake.nix diff --git a/home/programs/tui/nvf/keymaps.nix b/home/nvf/keymaps.nix similarity index 100% rename from home/programs/tui/nvf/keymaps.nix rename to home/nvf/keymaps.nix diff --git a/home/programs/tui/nvf/languages.nix b/home/nvf/languages.nix similarity index 100% rename from home/programs/tui/nvf/languages.nix rename to home/nvf/languages.nix diff --git a/home/programs/tui/nvf/mini.nix b/home/nvf/mini.nix similarity index 100% rename from home/programs/tui/nvf/mini.nix rename to home/nvf/mini.nix diff --git a/home/programs/tui/nvf/options.nix b/home/nvf/options.nix similarity index 100% rename from home/programs/tui/nvf/options.nix rename to home/nvf/options.nix diff --git a/home/programs/tui/nvf/picker.nix b/home/nvf/picker.nix similarity index 100% rename from home/programs/tui/nvf/picker.nix rename to home/nvf/picker.nix diff --git a/home/programs/tui/nvf/snacks.nix b/home/nvf/snacks.nix similarity index 100% rename from home/programs/tui/nvf/snacks.nix rename to home/nvf/snacks.nix diff --git a/home/programs/tui/nvf/utils.nix b/home/nvf/utils.nix similarity index 100% rename from home/programs/tui/nvf/utils.nix rename to home/nvf/utils.nix diff --git a/home/programs/gui/proton/default.nix b/home/programs/gui/proton/default.nix deleted file mode 100644 index ef3354b9..00000000 --- a/home/programs/gui/proton/default.nix +++ /dev/null @@ -1,36 +0,0 @@ -{ - pkgs, - config, - lib, - ... -}: { - home.packages = with pkgs; [ - proton-pass - ]; - - # Fix Proton Authenticator desktop entry - xdg.desktopEntries = { - "Proton Calendar" = { - name = "Proton Calendar"; - exec = ''${config.programs.helium.package}/bin/helium "https://calendar.proton.me"''; - icon = "proton-calendar"; - type = "Application"; - categories = ["Utility"]; - terminal = false; - }; - "Proton Mail" = { - name = "Proton Mail"; - exec = ''${config.programs.helium.package}/bin/helium "https://mail.proton.me/"''; - icon = "proton-mail"; - type = "Application"; - categories = ["Utility"]; - terminal = false; - }; - }; - - home.persistence."/persist" = lib.mkIf (config.var.impermanenceEnabled or false) { - directories = [ - ".config/Proton Pass" - ]; - }; -} diff --git a/home/programs/tui/git/default.nix b/home/programs/tui/git/default.nix deleted file mode 100644 index 3b24f109..00000000 --- a/home/programs/tui/git/default.nix +++ /dev/null @@ -1,52 +0,0 @@ -# Git configuration -{config, ...}: let - username = config.var.git.username; - email = config.var.git.email; -in { - programs.git = { - enable = true; - ignores = [ - ".cache/" - ".DS_Store" - ".idea/" - "*.swp" - "*.elc" - "auto-save-list" - ".direnv/" - "node_modules" - "result" - "result-*" - ".superpowers/" - ".claude/" - "docs/superpowers/" - ]; - settings = { - user.name = username; - user.email = email; - init.defaultBranch = "main"; - pull.rebase = "true"; - push.autoSetupRemote = true; - color.ui = "1"; - alias = { - co = "checkout"; - fuck = "commit --amend -m"; - c = "commit -m"; - ca = "commit -am"; - forgor = "commit --amend --no-edit"; - graph = "log --all --decorate --graph --oneline"; - oops = "checkout --"; - l = "log"; - r = "rebase"; - s = "status --short"; - ss = "status"; - d = "diff"; - ps = "!git push origin $(git rev-parse --abbrev-ref HEAD)"; - pl = "!git pull origin $(git rev-parse --abbrev-ref HEAD)"; - st = "status"; - br = "branch"; - hist = ''log --pretty=format:"%Cgreen%h %Creset%cd %Cblue[%cn] %Creset%s%C(yellow)%d%C(reset)" --graph --date=relative --decorate --all''; - llog = ''log --graph --name-status --pretty=format:"%C(red)%h %C(reset)(%cd) %C(green)%an %Creset%s %C(yellow)%d%Creset" --date=relative''; - }; - }; - }; -} diff --git a/home/programs/tui/wikiman/default.nix b/home/programs/tui/wikiman/default.nix deleted file mode 100644 index f04da971..00000000 --- a/home/programs/tui/wikiman/default.nix +++ /dev/null @@ -1,49 +0,0 @@ -{ - pkgs, - lib, - ... -}: let - # wikiman ships without the ArchWiki/tldr-pages databases (too heavy to - # bundle). These are fetched declaratively from wikiman's own release - # snapshots and baked into a wrapped `wikiman` so `-S` shows them as - # installed offline, no manual `make source-*` step required. - # To refresh: bump the release tag/date below and update the hashes - # (`nix hash file --sri `). - # - # Download size (compressed): ~17M ArchWiki + ~3.4M tldr-pages. - # Store size (unpacked): ~239M ArchWiki + ~147M tldr-pages (~385M total). - archWikiSrc = pkgs.fetchurl { - url = "https://github.com/filiparag/wikiman/releases/download/2.14.1/arch-wiki_20260810.source.tar.xz"; - hash = "sha256-82aiDvwZ07m9CfBVYIDLSUpWds4QxUbCbCPmQ26j1XI="; - }; - tldrPagesSrc = pkgs.fetchurl { - url = "https://github.com/filiparag/wikiman/releases/download/2.14.1/tldr-pages_20260810.source.tar.xz"; - hash = "sha256-2vdszVMImSN1UF+OepKdj1v+lsG2jM68gcpnUJyqddw="; - }; - - # Real files (not symlinks): wikiman's source-detection does `find -type f` - # on this dir, which doesn't match symlinks, so `pkgs.symlinkJoin` alone - # won't work here. - data = pkgs.runCommand "wikiman-data" {nativeBuildInputs = [pkgs.xz];} '' - mkdir -p $out - cp -r ${pkgs.wikiman}/share $out/share - chmod -R u+w $out/share - tar xf ${archWikiSrc} -C $out --strip-components=1 - tar xf ${tldrPagesSrc} -C $out --strip-components=1 - ''; - - wikiman-full = pkgs.symlinkJoin { - name = "wikiman-full"; - paths = [pkgs.wikiman]; - nativeBuildInputs = [pkgs.makeWrapper]; - postBuild = '' - rm $out/bin/wikiman - makeWrapper ${pkgs.wikiman}/bin/.wikiman-wrapped $out/bin/wikiman \ - --prefix PATH : "${lib.makeBinPath [pkgs.fzf pkgs.ripgrep pkgs.gawk pkgs.w3m pkgs.coreutils pkgs.parallel]}" \ - --set conf_sys_usr "${data}" - ''; - meta.mainProgram = "wikiman"; - }; -in { - home.packages = [wikiman-full]; # Offline search engine for manual pages, ArchWiki and tldr -} diff --git a/home/system/clipboard/default.nix b/home/system/clipboard/default.nix index 01ce4449..03f0dfda 100644 --- a/home/system/clipboard/default.nix +++ b/home/system/clipboard/default.nix @@ -3,8 +3,19 @@ pkgs, scripts, ... -}: { - home.packages = [pkgs.wl-clipboard]; +}: let + tofiMenu = "${pkgs.tofi}/bin/tofi --horizontal false --anchor center --width 700 --height 500 --margin-top 0 --margin-left 0 --margin-right 0 --num-results 10"; +in { + scripts.clipboard-menu = pkgs.writeShellScriptBin "clipboard-menu" '' + list=$(${pkgs.cliphist}/bin/cliphist list) + selected=$(printf '%s\n' "$list" | cut -f2- | ${tofiMenu} --prompt-text "Clipboard: ") + [ -n "$selected" ] && printf '%s\n' "$list" \ + | awk -F'\t' -v s="$selected" '$2 == s {print; exit}' \ + | ${pkgs.cliphist}/bin/cliphist decode \ + | ${pkgs.wl-clipboard}/bin/wl-copy + ''; + + home.packages = [pkgs.wl-clipboard scripts.clipboard-menu]; services.cliphist = { enable = true; diff --git a/home/system/hypridle/default.nix b/home/system/hypridle/default.nix index a5931a97..62bd0d23 100644 --- a/home/system/hypridle/default.nix +++ b/home/system/hypridle/default.nix @@ -1,6 +1,24 @@ # hypridle handles idle management: lock the screen, turn the display off, and # suspend after periods of inactivity. The `caffeine-toggle` script pauses it. -{pkgs, ...}: { +{ + pkgs, + scripts, + ... +}: { + scripts.caffeine-toggle = pkgs.writeShellScriptBin "caffeine-toggle" '' + # Pause hypridle (stay awake) or resume it. + if systemctl --user is-active --quiet hypridle; then + systemctl --user stop hypridle + OSD_TEXT="󰅶 Keep Awake On" + else + systemctl --user start hypridle + OSD_TEXT="󰾫 Keep Awake Off" + fi + ${scripts.waybar-osd}/bin/waybar-osd "$OSD_TEXT" + ''; + + home.packages = [scripts.caffeine-toggle]; + services.hypridle = { enable = true; settings = { @@ -17,7 +35,7 @@ on-timeout = "loginctl lock-session"; } { - timeout = 360; # 6 min → screen off + timeout = 720; # 12 min → screen off on-timeout = "${pkgs.hyprland}/bin/hyprctl dispatch dpms off"; on-resume = "${pkgs.hyprland}/bin/hyprctl dispatch dpms on"; } @@ -28,4 +46,16 @@ ]; }; }; + + xdg.desktopEntries = { + caffeine-toggle = { + name = "Keep Awake"; + exec = "${scripts.caffeine-toggle}/bin/caffeine-toggle"; + icon = "my-caffeine-on-symbolic"; + comment = "Pause or resume idle locking and suspend"; + categories = ["System"]; + terminal = false; + settings.Keywords = "caffeine;idle;awake;inhibit;suspend;"; + }; + }; } diff --git a/home/system/hyprland/bindings.nix b/home/system/hyprland/bindings.nix index db0c448f..b4ea7c5b 100644 --- a/home/system/hyprland/bindings.nix +++ b/home/system/hyprland/bindings.nix @@ -46,63 +46,6 @@ in { bind = [ - # Applications - ( - "$shiftMod, A, exec, " - + lib.getExe (mkMenu [ - { - key = "a"; - desc = "Proton Authenticator"; - cmd = "env WEBKIT_DISABLE_COMPOSITING_MODE=1 ${pkgs.proton-authenticator}/bin/proton-authenticator"; - } - { - key = "p"; - desc = "Proton Pass"; - cmd = "${pkgs.proton-pass}/bin/proton-pass"; - } - { - key = "v"; - desc = "Proton VPN"; - cmd = "${pkgs.proton-vpn}/bin/protonvpn-app"; - } - { - key = "c"; - desc = "Proton Calendar"; - cmd = "${config.programs.helium.package}/bin/helium 'https://calendar.proton.me/'"; - } - { - key = "m"; - desc = "Proton Mail"; - cmd = "${config.programs.helium.package}/bin/helium 'https://mail.proton.me/'"; - } - { - key = "o"; - desc = "Obsidian"; - cmd = "${pkgs.obsidian}/bin/obsidian"; - } - { - key = "s"; - desc = "Signal"; - cmd = "${pkgs.signal-desktop}/bin/signal-desktop"; - } - { - key = "t"; - desc = "TickTick"; - cmd = "${pkgs.ticktick}/bin/ticktick"; - } - { - key = "b"; - desc = "Helium"; - cmd = "${config.programs.helium.package}/bin/helium"; - } - { - key = "i"; - desc = "Helium (Incognito)"; - cmd = "${config.programs.helium.package}/bin/helium --incognito"; - } - ]) - ) - "$mod,B, exec, uwsm app -- ${config.programs.helium.package}/bin/helium" # Browser # Power @@ -112,22 +55,22 @@ in { { key = "l"; desc = "Lock"; - cmd = "${pkgs.hyprlock}/bin/hyprlock"; + cmd = config.xdg.desktopEntries.lock.exec; } { key = "s"; desc = "Suspend"; - cmd = "systemctl suspend"; + cmd = config.xdg.desktopEntries.suspend.exec; } { key = "r"; desc = "Reboot"; - cmd = "systemctl reboot"; + cmd = config.xdg.desktopEntries.reboot.exec; } { key = "p"; desc = "Power Off"; - cmd = "systemctl poweroff"; + cmd = config.xdg.desktopEntries.shutdown.exec; } ]) ) @@ -159,8 +102,8 @@ in { "$shiftMod, S, movetoworkspace, special:scratch" # Move to scratch workspace # Utilities - ", Print, exec, ${pkgs.hyprshot}/bin/hyprshot -m region" # Capture region - "$shiftMod, Print, exec, ${pkgs.hyprshot}/bin/hyprshot -m output" # Capture screen + ", Print, exec, ${config.xdg.desktopEntries.screenshot-region.exec}" # Capture region + "$shiftMod, Print, exec, ${config.xdg.desktopEntries.screenshot-screen.exec}" # Capture screen ] ++ (builtins.concatLists ( builtins.genList ( diff --git a/home/system/hyprland/default.nix b/home/system/hyprland/default.nix index ae3524bf..4f5aea6e 100644 --- a/home/system/hyprland/default.nix +++ b/home/system/hyprland/default.nix @@ -21,6 +21,7 @@ in { ./bindings.nix ./polkitagent.nix ./hyprpaper.nix + ./scripts.nix ]; home.packages = diff --git a/home/system/hyprland/scripts.nix b/home/system/hyprland/scripts.nix new file mode 100644 index 00000000..b4bd9623 --- /dev/null +++ b/home/system/hyprland/scripts.nix @@ -0,0 +1,61 @@ +# Compositor-level scripts: focus mode (temporarily flattens Hyprland's +# animations/gaps/decoration) and night shift (hyprsunset). +{ + pkgs, + scripts, + ... +}: { + scripts.focus-toggle = pkgs.writeShellScriptBin "focus-toggle" '' + if test -f "$XDG_RUNTIME_DIR/hypr-focus-mode"; then + rm "$XDG_RUNTIME_DIR/hypr-focus-mode" + OSD_TEXT="󰈈 Focus Off" + ${scripts.waybar-osd}/bin/waybar-osd "$OSD_TEXT" + ${pkgs.hyprland}/bin/hyprctl reload + ${pkgs.hyprland}/bin/hyprctl dispatch exec waybar + else + touch "$XDG_RUNTIME_DIR/hypr-focus-mode" + OSD_TEXT="󰈈 Focus On" + ${scripts.waybar-osd}/bin/waybar-osd "$OSD_TEXT" + ${pkgs.procps}/bin/pkill waybar || true + ${pkgs.hyprland}/bin/hyprctl keyword animations:enabled false + ${pkgs.hyprland}/bin/hyprctl keyword general:gaps_in 0 + ${pkgs.hyprland}/bin/hyprctl keyword general:gaps_out 0 + ${pkgs.hyprland}/bin/hyprctl keyword decoration:active_opacity 1 + ${pkgs.hyprland}/bin/hyprctl keyword decoration:inactive_opacity 1 + ${pkgs.hyprland}/bin/hyprctl keyword decoration:rounding 0 + fi + ''; + + scripts.nightshift-toggle = pkgs.writeShellScriptBin "nightshift-toggle" '' + if ${pkgs.procps}/bin/pidof "hyprsunset" > /dev/null; then + pkill hyprsunset + OSD_TEXT="󰖔 Night Shift Off" + else + ${pkgs.hyprsunset}/bin/hyprsunset -t 4500 & + OSD_TEXT="󰖔 Night Shift On" + fi + ${scripts.waybar-osd}/bin/waybar-osd "$OSD_TEXT" + ''; + + home.packages = [scripts.focus-toggle scripts.nightshift-toggle]; + + xdg.desktopEntries = { + focus-toggle = { + name = "Focus Mode"; + exec = "${scripts.focus-toggle}/bin/focus-toggle"; + icon = "do-not-disturb-symbolic"; + comment = "Toggle focus mode"; + categories = ["System"]; + terminal = false; + }; + + nightshift-toggle = { + name = "Night Shift"; + exec = "${scripts.nightshift-toggle}/bin/nightshift-toggle"; + icon = "night-light-symbolic"; + comment = "Toggle night shift"; + categories = ["System"]; + terminal = false; + }; + }; +} diff --git a/home/system/hyprlock/default.nix b/home/system/hyprlock/default.nix index aa8c5182..2b726176 100644 --- a/home/system/hyprlock/default.nix +++ b/home/system/hyprlock/default.nix @@ -63,6 +63,15 @@ in { stylix.targets.hyprlock.enable = false; + xdg.desktopEntries.lock = { + name = "Lock"; + exec = "${pkgs.hyprlock}/bin/hyprlock"; + icon = "system-lock-screen-symbolic"; + comment = "Lock the screen"; + categories = ["System"]; + terminal = false; + }; + programs.hyprlock = { enable = true; settings = { diff --git a/home/system/mime/default.nix b/home/system/mime/default.nix index a7a557b0..ca470076 100644 --- a/home/system/mime/default.nix +++ b/home/system/mime/default.nix @@ -8,11 +8,11 @@ text = ["nvim-ghostty.desktop"]; code = ["nvim-ghostty.desktop"]; image = ["imv-dir.desktop"]; - audio = ["vlc.desktop"]; + audio = ["kew.desktop"]; video = ["vlc.desktop"]; directory = ["elio.desktop"]; office = ["onlyoffice-desktopeditors.desktop"]; - pdf = ["onlyoffice-desktopeditors.desktop"]; + pdf = ["helium.desktop"]; archive = ["elio.desktop"]; browser = ["helium.desktop"]; }; @@ -53,21 +53,24 @@ "image/bmp" "image/gif" "image/jpeg" - "image/jpg" "image/png" "image/svg+xml" "image/tiff" "image/vnd.microsoft.icon" "image/webp" + "image/heif" + "image/avif" ]; audio = [ "audio/aac" "audio/mpeg" "audio/ogg" "audio/opus" - "audio/wav" + "audio/vnd.wave" "audio/webm" "audio/x-matroska" + "audio/flac" + "audio/mp4" ]; video = [ "video/mp2t" @@ -78,6 +81,7 @@ "video/x-flv" "video/x-matroska" "video/x-msvideo" + "video/quicktime" ]; directory = ["inode/directory"]; office = [ @@ -104,6 +108,8 @@ "application/x-xz" "application/x-zstd" "application/x-compressed-tar" + "application/x-bzip2-compressed-tar" + "application/x-xz-compressed-tar" ]; browser = [ "text/html" @@ -145,7 +151,6 @@ in { enable = true; createDirectories = true; desktop = null; - music = null; publicShare = null; templates = null; extraConfig = { diff --git a/home/system/power/default.nix b/home/system/power/default.nix new file mode 100644 index 00000000..e7651387 --- /dev/null +++ b/home/system/power/default.nix @@ -0,0 +1,42 @@ +{ + pkgs, + scripts, + ... +}: { + scripts.power-cycle = pkgs.writeShellScriptBin "power-cycle" '' + ppd=${pkgs.power-profiles-daemon}/bin/powerprofilesctl + cur=$("$ppd" get) + case "$cur" in + power-saver) next=balanced; icon="󰾅" ;; + balanced) next=performance; icon="󰓅" ;; + performance) next=power-saver; icon="󰌪" ;; + *) next=balanced; icon="󰾅" ;; + esac + "$ppd" set "$next" + OSD_TEXT="$icon ''${next^}" + ${scripts.waybar-osd}/bin/waybar-osd "$OSD_TEXT" + ''; + + home.packages = [pkgs.poweralertd scripts.power-cycle]; + + xdg.desktopEntries.power-cycle = { + name = "Power Profile"; + exec = "${scripts.power-cycle}/bin/power-cycle"; + icon = "power-profile-balanced-symbolic"; + comment = "Cycle power-saver / balanced / performance"; + categories = ["System"]; + terminal = false; + settings.Keywords = "power;profile;performance;battery;"; + }; + + # Event-driven low-battery/critical/full notifications via UPower dbus signals + # (thresholds set in nixos/utils.nix, services.upower.percentage*). + systemd.user.services.poweralertd = { + Unit.Description = "UPower-powered battery notifications"; + Service = { + ExecStart = "${pkgs.poweralertd}/bin/poweralertd"; + Restart = "on-failure"; + }; + Install.WantedBy = ["graphical-session.target"]; + }; +} diff --git a/home/system/scripts/default.nix b/home/system/scripts/default.nix new file mode 100644 index 00000000..03675e2c --- /dev/null +++ b/home/system/scripts/default.nix @@ -0,0 +1,16 @@ +# Shared script registry: any module that owns a script contributes it here +# (`scripts. = ...`), and every module reads it back via the `scripts` +# module argument. +{ + lib, + config, + ... +}: { + options.scripts = lib.mkOption { + type = lib.types.attrsOf lib.types.package; + default = {}; + internal = true; + }; + + config._module.args.scripts = config.scripts; +} diff --git a/home/system/swaync/default.nix b/home/system/swaync/default.nix index 1ad2a3ce..410a1cf5 100644 --- a/home/system/swaync/default.nix +++ b/home/system/swaync/default.nix @@ -18,6 +18,28 @@ in "${builtins.substring high 1 digits}${builtins.substring low 1 digits}"; alphaHex = opacityToHex config.theme.inactive-opacity; in { + scripts.dnd-toggle = pkgs.writeShellScriptBin "dnd-toggle" '' + state=$(${pkgs.swaynotificationcenter}/bin/swaync-client -d) + if [ "$state" = "true" ]; then + OSD_TEXT="󰂛 Do Not Disturb On" + else + OSD_TEXT="󰂚 Do Not Disturb Off" + fi + ${scripts.waybar-osd}/bin/waybar-osd "$OSD_TEXT" + ''; + + home.packages = [scripts.dnd-toggle]; + + xdg.desktopEntries.dnd-toggle = { + name = "Do Not Disturb"; + exec = "${scripts.dnd-toggle}/bin/dnd-toggle"; + icon = "notifications-disabled-symbolic"; + comment = "Toggle Do Not Disturb"; + categories = ["System"]; + terminal = false; + settings.Keywords = "dnd;notifications;disturb;swaync;silence;"; + }; + services.swaync = { enable = true; @@ -409,13 +431,5 @@ in { stylix.targets.swaync.enable = false; - # GTK 4.22 defaults to the Vulkan renderer, which compiles its graphics - # pipelines lazily on the first frame. The control center has many distinct - # visual elements, so the first open triggers a big burst of pipeline - # compilation (a multi-second stall on a cold boot) while later opens reuse - # the in-process cache. The GL (ngl) renderer avoids this: it stays - # GPU-accelerated and benefits from Mesa's on-disk shader cache, so the - # first open is as fast as the rest. Scoped to swaync so other GTK4 apps - # keep the Vulkan renderer. systemd.user.services.swaync.Service.Environment = ["GSK_RENDERER=ngl"]; } diff --git a/home/system/termfilechooser/default.nix b/home/system/termfilechooser/default.nix index 8c14176d..695cbb26 100644 --- a/home/system/termfilechooser/default.nix +++ b/home/system/termfilechooser/default.nix @@ -1,6 +1,5 @@ # Use elio as the file picker for portal dialogs (browser "select file(s)" and -# "save download to..."). The backend is xdg-desktop-portal-termfilechooser, -# enabled system-wide in nixos/utils.nix (extraPortals + FileChooser routing). +# "save download to..."). { config, pkgs, @@ -48,9 +47,6 @@ fi fi ''; - # ghostty must run in the foreground instead of handing off to the - # single-instance daemon, otherwise the wrapper returns before you've picked - # anything and the portal reads an empty selection. termcmd = "ghostty --gtk-single-instance=false --title=termfilechooser -e"; in { xdg.configFile."xdg-desktop-portal-termfilechooser/config".text = '' @@ -60,6 +56,6 @@ in { open_mode=suggested save_mode=suggested env=TERMCMD=${termcmd} - PATH=${config.home.profileDirectory}/bin:/run/current-system/sw/bin:/run/wrappers/bin + PATH=${config.home.profileDirectory}/bin:/run/current-system/sw/bin:/run/wrappers/bin ''; } diff --git a/home/system/tofi/default.nix b/home/system/tofi/default.nix index c1684f90..99eca0a9 100644 --- a/home/system/tofi/default.nix +++ b/home/system/tofi/default.nix @@ -12,7 +12,7 @@ then barHeight / 2 else config.theme.rounding; in { - imports = [./desktop-actions.nix]; + imports = [./desktop-actions.nix ./scripts.nix]; programs.tofi = { enable = true; settings = { diff --git a/home/system/tofi/desktop-actions.nix b/home/system/tofi/desktop-actions.nix index a5e28ec1..ca8f6e96 100644 --- a/home/system/tofi/desktop-actions.nix +++ b/home/system/tofi/desktop-actions.nix @@ -4,24 +4,6 @@ ... }: { xdg.desktopEntries = { - focus-toggle = { - name = "Focus Mode"; - exec = "${scripts.focus-toggle}/bin/focus-toggle"; - icon = "do-not-disturb-symbolic"; - comment = "Toggle focus mode"; - categories = ["System"]; - terminal = false; - }; - - nightshift-toggle = { - name = "Night Shift"; - exec = "${scripts.nightshift-toggle}/bin/nightshift-toggle"; - icon = "night-light-symbolic"; - comment = "Toggle night shift"; - categories = ["System"]; - terminal = false; - }; - mic-mute = { name = "Mute Microphone"; exec = "${scripts.mic-mute}/bin/mic-mute"; @@ -31,15 +13,6 @@ terminal = false; }; - lock = { - name = "Lock"; - exec = "${pkgs.hyprlock}/bin/hyprlock"; - icon = "system-lock-screen-symbolic"; - comment = "Lock the screen"; - categories = ["System"]; - terminal = false; - }; - reboot = { name = "Reboot"; exec = "systemctl reboot"; @@ -49,6 +22,15 @@ terminal = false; }; + suspend = { + name = "Suspend"; + exec = "systemctl suspend"; + icon = "system-suspend-symbolic"; + comment = "Suspend the system"; + categories = ["System"]; + terminal = false; + }; + shutdown = { name = "Shutdown"; exec = "systemctl poweroff"; @@ -67,15 +49,6 @@ terminal = false; }; - waybar-toggle = { - name = "Toggle Waybar"; - exec = "${scripts.waybar-toggle}/bin/waybar-toggle"; - icon = "panel-applets-symbolic"; - comment = "Show or hide the status bar"; - categories = ["System"]; - terminal = false; - }; - wifi-toggle = { name = "Toggle Wi-Fi"; exec = "${scripts.wifi-toggle}/bin/wifi-toggle"; @@ -154,16 +127,6 @@ settings.Keywords = "record;recording;screencast;video;"; }; - power-cycle = { - name = "Power Profile"; - exec = "${scripts.power-cycle}/bin/power-cycle"; - icon = "power-profile-balanced-symbolic"; - comment = "Cycle power-saver / balanced / performance"; - categories = ["System"]; - terminal = false; - settings.Keywords = "power;profile;performance;battery;"; - }; - airplane-toggle = { name = "Airplane Mode"; exec = "${scripts.airplane-toggle}/bin/airplane-toggle"; @@ -194,16 +157,6 @@ settings.Keywords = "icon;nerdfont;glyph;symbol;"; }; - caffeine-toggle = { - name = "Keep Awake"; - exec = "${scripts.caffeine-toggle}/bin/caffeine-toggle"; - icon = "my-caffeine-on-symbolic"; - comment = "Pause or resume idle locking and suspend"; - categories = ["System"]; - terminal = false; - settings.Keywords = "caffeine;idle;awake;inhibit;suspend;"; - }; - logout = { name = "Logout"; exec = "${pkgs.hyprland}/bin/hyprctl dispatch exit"; @@ -213,16 +166,6 @@ terminal = false; }; - dnd-toggle = { - name = "Do Not Disturb"; - exec = "${scripts.dnd-toggle}/bin/dnd-toggle"; - icon = "notifications-disabled-symbolic"; - comment = "Toggle Do Not Disturb"; - categories = ["System"]; - terminal = false; - settings.Keywords = "dnd;notifications;disturb;swaync;silence;"; - }; - vol-mute = { name = "Mute Volume"; exec = "${scripts.vol-mute}/bin/vol-mute"; diff --git a/home/system/tofi/scripts.nix b/home/system/tofi/scripts.nix new file mode 100644 index 00000000..db29cc6a --- /dev/null +++ b/home/system/tofi/scripts.nix @@ -0,0 +1,35 @@ +# Picker scripts built on tofi's dmenu mode: emoji and Nerd Font icon input. +{ + pkgs, + config, + scripts, + ... +}: let + tofiMenu = "${pkgs.tofi}/bin/tofi --horizontal false --anchor center --width 700 --height 500 --margin-top 0 --margin-left 0 --margin-right 0 --num-results 10"; + + nerdFontGlyphnames = pkgs.fetchurl { + url = "https://raw.githubusercontent.com/ryanoasis/nerd-fonts/v3.4.0/glyphnames.json"; + sha256 = "sha256-4tENI/W/8L1vBnbpsB2XifzcZW3ntJiilVwncW6kQ5w="; + }; + nerdFontIconList = pkgs.runCommand "nerd-font-icons.txt" {nativeBuildInputs = [pkgs.jq];} '' + jq -r 'to_entries[] | select(.key != "METADATA") | "\(.value.char) \(.key)"' \ + ${nerdFontGlyphnames} > "$out" + ''; +in { + scripts.emoji-picker = pkgs.writeShellScriptBin "emoji-picker" '' + export PATH="${pkgs.wtype}/bin:${pkgs.wl-clipboard}/bin:$PATH" + export BEMOJI_PICKER_CMD="${tofiMenu} --prompt-text 'emoji: '" + # -t types the emoji, -c also copies it. + exec ${pkgs.bemoji}/bin/bemoji -t -c + ''; + + scripts.icon-picker = pkgs.writeShellScriptBin "icon-picker" '' + selected=$(${tofiMenu} --font "${config.stylix.fonts.monospace.name}" --prompt-text 'icon: ' < ${nerdFontIconList}) + [ -z "$selected" ] || icon=$(printf '%s\n' "$selected" | awk '{print $1}') + [ -n "''${icon:-}" ] || exit 0 + ${pkgs.wtype}/bin/wtype "$icon" + printf '%s' "$icon" | ${pkgs.wl-clipboard}/bin/wl-copy + ''; + + home.packages = [scripts.emoji-picker scripts.icon-picker]; +} diff --git a/home/system/udiskie/default.nix b/home/system/udiskie/default.nix index bb59f1de..f31ac055 100644 --- a/home/system/udiskie/default.nix +++ b/home/system/udiskie/default.nix @@ -2,7 +2,7 @@ { services.udiskie = { enable = true; - notify = true; + notify = false; automount = true; tray = "never"; }; diff --git a/home/system/waybar/battery-monitor.sh b/home/system/waybar/battery-monitor.sh deleted file mode 100644 index 611202ff..00000000 --- a/home/system/waybar/battery-monitor.sh +++ /dev/null @@ -1,103 +0,0 @@ -# battery-monitor: low-battery alerts for waybar/swaync. -# Runs main once (triggered by the battery-monitor systemd timer). - -POWER_SUPPLY_DIR="${POWER_SUPPLY_DIR:-/sys/class/power_supply}" -STATE_FILE="${BATTERY_STATE_FILE:-/tmp/battery-alert-state}" -CRIT_ID_FILE="${BATTERY_CRIT_ID_FILE:-/tmp/battery-crit-id}" - -WARN_THRESHOLD=10 -CRIT_THRESHOLD=5 - -# Pure decision. Prints ":". -# action ∈ noop | osd_warn | crit_show | crit_clear ; state ∈ none | warn10 | crit5 -battery_decide() { - status=$1 - cap=$2 - prev=$3 - - if [ "$status" = "Discharging" ]; then - if [ "$cap" -le "$CRIT_THRESHOLD" ]; then - echo "crit_show:crit5" - elif [ "$cap" -le "$WARN_THRESHOLD" ]; then - if [ "$prev" = "crit5" ]; then - echo "crit_clear:warn10" - elif [ "$prev" = "warn10" ]; then - echo "noop:warn10" - else - echo "osd_warn:warn10" - fi - else - if [ "$prev" = "crit5" ]; then - echo "crit_clear:none" - else - echo "noop:none" - fi - fi - else - if [ "$prev" = "crit5" ]; then - echo "crit_clear:none" - else - echo "noop:none" - fi - fi -} - -# First real battery (type == Battery, with status + capacity). -resolve_battery() { - for d in "$POWER_SUPPLY_DIR"/*; do - [ -r "$d/type" ] || continue - [ "$(cat "$d/type")" = "Battery" ] || continue - [ -r "$d/status" ] && [ -r "$d/capacity" ] || continue - printf '%s' "$d" - return 0 - done - return 1 -} - -show_warn_osd() { - waybar-osd "󰂃 Low battery · $1%" -} - -show_crit_notification() { - cap=$1 - id=$(cat "$CRIT_ID_FILE" 2>/dev/null || echo 0) - newid=$(notify-send --print-id --replace-id="$id" \ - --urgency=critical --expire-time=0 \ - "󰂃 Critical battery" "Battery at $cap%: plug in the charger") - printf '%s' "$newid" >"$CRIT_ID_FILE" -} - -clear_crit_notification() { - id=$(cat "$CRIT_ID_FILE" 2>/dev/null || echo 0) - if [ "$id" != "0" ]; then - gdbus call --session \ - --dest org.freedesktop.Notifications \ - --object-path /org/freedesktop/Notifications \ - --method org.freedesktop.Notifications.CloseNotification "$id" \ - >/dev/null 2>&1 || true - fi - rm -f "$CRIT_ID_FILE" -} - -main() { - dir=$(resolve_battery) || exit 0 - - status=$(cat "$dir/status") - cap=$(cat "$dir/capacity") - prev=$(cat "$STATE_FILE" 2>/dev/null || echo none) - - result=$(battery_decide "$status" "$cap" "$prev") - action=${result%%:*} - newstate=${result##*:} - - case "$action" in - osd_warn) show_warn_osd "$cap" ;; - crit_show) show_crit_notification "$cap" ;; - crit_clear) clear_crit_notification ;; - noop) : ;; - esac - - printf '%s' "$newstate" >"$STATE_FILE" -} - -main "$@" diff --git a/home/system/waybar/default.nix b/home/system/waybar/default.nix index e3c49004..09dcbbe1 100644 --- a/home/system/waybar/default.nix +++ b/home/system/waybar/default.nix @@ -2,23 +2,13 @@ pkgs, config, ... -}: let - scripts = import ./scripts.nix {inherit pkgs config;}; -in { +}: { imports = [ + ./scripts ./settings.nix ./style.nix ]; - _module.args.scripts = scripts; - _module.args.osdPath = scripts.osdPath; - _module.args.networkScript = scripts.networkScript; - _module.args.bluetoothScript = scripts.bluetoothScript; - _module.args.volMuteScript = scripts.vol-mute; - _module.args.caffeineToggleScript = scripts.caffeine-toggle; - _module.args.osdStatusScript = scripts.waybar-osd-status; - _module.args.nightshiftToggleScript = scripts.nightshift-toggle; - programs.waybar.enable = true; stylix.targets.waybar.enable = false; @@ -26,35 +16,19 @@ in { [ playerctl pavucontrol - blueman hyprsunset ] - ++ (with scripts; [waybar-osd waybar-osd-status battery-monitor vol-up vol-down vol-mute mic-mute bright-up bright-down nightshift-toggle focus-toggle waybar-toggle wifi-toggle bluetooth-toggle dnd-toggle output-cycle input-cycle color-pick screenshot-edit record-toggle power-cycle airplane-toggle clipboard-menu emoji-picker caffeine-toggle mic-status]); + ++ (with config.scripts; [waybar-osd waybar-osd-status vol-up vol-down vol-mute mic-mute bright-up bright-down waybar-toggle wifi-toggle bluetooth-toggle output-cycle input-cycle color-pick screenshot-edit record-toggle airplane-toggle mic-status]); - # Poll battery level every 30s; battery-monitor no-ops when no battery exists. - systemd.user.services.battery-monitor = { - Unit.Description = "Low-battery OSD and critical notification monitor"; - Service = { - Type = "oneshot"; - ExecStart = "${scripts.battery-monitor}/bin/battery-monitor"; - }; + xdg.desktopEntries.waybar-toggle = { + name = "Toggle Waybar"; + exec = "${config.scripts.waybar-toggle}/bin/waybar-toggle"; + icon = "panel-applets-symbolic"; + comment = "Show or hide the status bar"; + categories = ["System"]; + terminal = false; }; - systemd.user.timers.battery-monitor = { - Unit.Description = "Poll battery level for low-battery alerts"; - Timer = { - OnBootSec = "1min"; - OnUnitActiveSec = "30s"; - }; - Install.WantedBy = ["timers.target"]; - }; - - # Prevent blueman-applet from auto-starting via XDG autostart (we use custom/bluetooth module instead) - xdg.configFile."autostart/blueman.desktop".text = '' - [Desktop Entry] - Hidden=true - ''; - wayland.windowManager.hyprland.settings.exec-once = [ "waybar" ]; diff --git a/home/system/waybar/scripts.nix b/home/system/waybar/scripts.nix deleted file mode 100644 index 53287112..00000000 --- a/home/system/waybar/scripts.nix +++ /dev/null @@ -1,456 +0,0 @@ -{ - pkgs, - config, -}: let - waybar-osd = pkgs.writeShellApplication { - name = "waybar-osd"; - runtimeInputs = with pkgs; [procps coreutils]; - text = '' - printf '%s' "$1" > "$XDG_RUNTIME_DIR/waybar-osd" - pkill -f -RTMIN+8 '^waybar$' 2>/dev/null || true - ''; - }; - - waybar-osd-status = pkgs.writeShellApplication { - name = "waybar-osd-status"; - runtimeInputs = with pkgs; [coreutils]; - text = '' - file="$XDG_RUNTIME_DIR/waybar-osd" - [ -f "$file" ] || exit 1 - mtime=$(stat -c %Y "$file" 2>/dev/null) || exit 1 - age=$(( $(date +%s) - mtime )) - if [ "$age" -ge 3 ]; then - rm -f "$file" - exit 1 - fi - ''; - }; - - # battery-monitor: low-battery alerts, run by the systemd user timer. - battery-monitor = pkgs.writeShellApplication { - name = "battery-monitor"; - runtimeInputs = with pkgs; [waybar-osd libnotify glib coreutils]; - text = builtins.readFile ./battery-monitor.sh; - }; - - updateOsd = '' - ${waybar-osd}/bin/waybar-osd "$OSD_TEXT" - ''; - - volGetText = '' - VOL_RAW=$(${pkgs.wireplumber}/bin/wpctl get-volume @DEFAULT_SINK@) - VOL=$(printf '%s' "$VOL_RAW" | awk '{printf "%d", $2*100}') - if printf '%s' "$VOL_RAW" | grep -q MUTED; then - OSD_TEXT="󰝟 $VOL%" - elif [ "$VOL" -lt 33 ]; then - OSD_TEXT="󰕿 $VOL%" - elif [ "$VOL" -lt 66 ]; then - OSD_TEXT="󰖀 $VOL%" - else - OSD_TEXT="󰕾 $VOL%" - fi - ''; - - brightGetText = '' - BRIGHT=$(${pkgs.brightnessctl}/bin/brightnessctl -m | awk -F, '{print int($5)}') - if [ "$BRIGHT" -lt 33 ]; then - OSD_TEXT="󰃞 $BRIGHT%" - elif [ "$BRIGHT" -lt 66 ]; then - OSD_TEXT="󰃟 $BRIGHT%" - else - OSD_TEXT="󰃠 $BRIGHT%" - fi - ''; - - # Resolve $src: the default source, otherwise the first available source. - # Some machines have no default audio source (@DEFAULT_AUDIO_SOURCE@ unresolved). - micSource = '' - src=$(${pkgs.wireplumber}/bin/wpctl inspect @DEFAULT_AUDIO_SOURCE@ 2>/dev/null | sed -n 's/^id \([0-9]*\),.*/\1/p') - if [ -z "$src" ]; then - src=$(${pkgs.pipewire}/bin/pw-dump | ${pkgs.jq}/bin/jq -r \ - '[.[] | select(.info.props."media.class"=="Audio/Source") | .id] | .[0] // empty') - fi - ''; - - # tofi in vertical dmenu mode: the global config is a 36px-tall horizontal - # launcher, unusable for a list, so override the geometry here. - tofiMenu = "${pkgs.tofi}/bin/tofi --horizontal false --anchor center --width 700 --height 500 --margin-top 0 --margin-left 0 --margin-right 0 --num-results 10"; - - # Name -> glyph table maintained by the nerd-fonts project itself, pinned to - # the same release as the nerd-fonts packages in nixos/fonts.nix. - nerdFontGlyphnames = pkgs.fetchurl { - url = "https://raw.githubusercontent.com/ryanoasis/nerd-fonts/v3.4.0/glyphnames.json"; - sha256 = "sha256-4tENI/W/8L1vBnbpsB2XifzcZW3ntJiilVwncW6kQ5w="; - }; - nerdFontIconList = pkgs.runCommand "nerd-font-icons.txt" {nativeBuildInputs = [pkgs.jq];} '' - jq -r 'to_entries[] | select(.key != "METADATA") | "\(.value.char) \(.key)"' \ - ${nerdFontGlyphnames} > "$out" - ''; - osdPath = "$XDG_RUNTIME_DIR/waybar-osd"; -in { - inherit waybar-osd waybar-osd-status battery-monitor osdPath; - - bluetoothScript = pkgs.writeShellScript "waybar-bluetooth" '' - jq=${pkgs.jq}/bin/jq - nl=$'\n' - # bluetoothctl hangs without a controller by default → always bounded by timeout. - bt() { timeout 3 ${pkgs.bluez}/bin/bluetoothctl "$@" 2>/dev/null; } - - powered=$(bt show | awk '/Powered:/ { print $2; exit }') - if [ "$powered" != "yes" ]; then - "$jq" -cn '{ text: "󰂲", class: "off", tooltip: "Bluetooth off" }' - exit 0 - fi - - tip="" - add_tip() { tip="''${tip:+$tip$nl}$1"; } - - count=0 - for mac in $(bt devices Connected | awk '{ print $2 }'); do - count=$((count + 1)) - info=$(bt info "$mac") - name=$(printf '%s' "$info" | sed -n 's/^[[:space:]]*Name: //p' | head -1) - [ -z "$name" ] && name="$mac" - batt=$(printf '%s' "$info" | sed -n 's/.*Battery Percentage:.*(\([0-9][0-9]*\)).*/\1/p' | head -1) - add_tip "󰂱 $name''${batt:+ · $batt%}" - done - - if [ "$count" -gt 0 ]; then - "$jq" -cn --arg tooltip "$tip" '{ text: "󰂰", class: "connected", tooltip: $tooltip }' - else - "$jq" -cn '{ text: "󰂰", class: "on", tooltip: "Bluetooth on" }' - fi - ''; - - networkScript = pkgs.writeShellScript "waybar-network" '' - nmcli=${pkgs.networkmanager}/bin/nmcli - ip=${pkgs.iproute2}/bin/ip - jq=${pkgs.jq}/bin/jq - nl=$'\n' - - text="" - tip="" - class="disconnected" - add_seg() { text="''${text:+$text }$1"; } - add_tip() { tip="''${tip:+$tip$nl}$1"; } - - # ── Ethernet ──────────────────────────────────────────────── - eth=$("$nmcli" -t -f DEVICE,TYPE,STATE device status 2>/dev/null \ - | awk -F: '$2 == "ethernet" && $3 == "connected" { print $1; exit }') - if [ -n "$eth" ]; then - eth_ip=$("$ip" -4 -br addr show "$eth" 2>/dev/null | awk '{ print $3 }' | cut -d/ -f1) - add_seg "󰛳" - class="ethernet" - add_tip "󰛳 Ethernet''${eth_ip:+ · $eth_ip}" - fi - - # ── Wi-Fi ─────────────────────────────────────────────────── - wifi=$("$nmcli" -t -f ACTIVE,SSID,SIGNAL device wifi 2>/dev/null | grep -m1 '^yes:') - if [ -n "$wifi" ]; then - ssid=$(printf '%s' "$wifi" | cut -d: -f2) - signal=$(printf '%s' "$wifi" | cut -d: -f3) - if [ "''${signal:-0}" -ge 80 ]; then icon="󰤨" - elif [ "''${signal:-0}" -ge 60 ]; then icon="󰤥" - elif [ "''${signal:-0}" -ge 40 ]; then icon="󰤢" - elif [ "''${signal:-0}" -ge 20 ]; then icon="󰤟" - else icon="󰤯" - fi - add_seg "$icon" - [ "$class" = "disconnected" ] && class="wifi" - add_tip "$icon ''${ssid:-Wi-Fi}''${signal:+ · $signal%}" - fi - - # ── VPN (nmcli, fallback interfaces) ──────────────────────── - vpn=$("$nmcli" -t -f TYPE,NAME connection show --active 2>/dev/null \ - | awk -F: '$1 == "vpn" || $1 == "wireguard" { print $2; exit }') - if [ -z "$vpn" ]; then - vpn=$("$ip" -br link show 2>/dev/null \ - | awk '($2 == "UP" || $2 == "UNKNOWN") && $1 ~ /^(tun|wg|proton|ppp)/ { sub(/@.*/, "", $1); print $1; exit }') - fi - if [ -n "$vpn" ]; then - add_seg "󰦝" - add_tip "󰦝 VPN · $vpn" - fi - - if [ -z "$text" ]; then - text="󰤭" - tip="Disconnected" - fi - - "$jq" -cn --arg text "$text" --arg class "$class" --arg tooltip "$tip" \ - '{ text: $text, class: $class, tooltip: $tooltip }' - ''; - - vol-up = pkgs.writeShellScriptBin "vol-up" '' - ${pkgs.wireplumber}/bin/wpctl set-volume @DEFAULT_SINK@ 5%+ --limit 1.0 - ${volGetText} - ${updateOsd} - ''; - - vol-down = pkgs.writeShellScriptBin "vol-down" '' - ${pkgs.wireplumber}/bin/wpctl set-volume @DEFAULT_SINK@ 5%- - ${volGetText} - ${updateOsd} - ''; - - vol-mute = pkgs.writeShellScriptBin "vol-mute" '' - ${pkgs.wireplumber}/bin/wpctl set-mute @DEFAULT_SINK@ toggle - ${volGetText} - ${updateOsd} - ''; - - mic-mute = pkgs.writeShellScriptBin "mic-mute" '' - wpctl=${pkgs.wireplumber}/bin/wpctl - ${micSource} - [ -z "$src" ] && exit 0 - - "$wpctl" set-mute "$src" toggle - if "$wpctl" get-volume "$src" | grep -q MUTED; then - OSD_TEXT="󰍭 Muted" - else - OSD_TEXT="󰍬 Live" - fi - ${updateOsd} - ''; - - mic-status = pkgs.writeShellScriptBin "mic-status" '' - ${micSource} - if [ -n "$src" ] && ${pkgs.wireplumber}/bin/wpctl get-volume "$src" | grep -q MUTED; then - echo true - else - echo false - fi - ''; - - bright-up = pkgs.writeShellScriptBin "bright-up" '' - ${pkgs.brightnessctl}/bin/brightnessctl set 5%+ - ${brightGetText} - ${updateOsd} - ''; - - bright-down = pkgs.writeShellScriptBin "bright-down" '' - ${pkgs.brightnessctl}/bin/brightnessctl set 5%- - ${brightGetText} - ${updateOsd} - ''; - - wifi-toggle = pkgs.writeShellScriptBin "wifi-toggle" '' - if ${pkgs.networkmanager}/bin/nmcli radio wifi | grep -q enabled; then - ${pkgs.networkmanager}/bin/nmcli radio wifi off - else - ${pkgs.networkmanager}/bin/nmcli radio wifi on - fi - ${updateOsd} - ''; - - bluetooth-toggle = pkgs.writeShellScriptBin "bluetooth-toggle" '' - if ${pkgs.bluez}/bin/bluetoothctl show | grep -q "Powered: yes"; then - ${pkgs.bluez}/bin/bluetoothctl power off - else - ${pkgs.bluez}/bin/bluetoothctl power on - fi - ${updateOsd} - ''; - - waybar-toggle = pkgs.writeShellScriptBin "waybar-toggle" '' - if pidof waybar > /dev/null; then - pkill waybar - else - hyprctl dispatch exec waybar - fi - ''; - - nightshift-toggle = pkgs.writeShellScriptBin "nightshift-toggle" '' - if ${pkgs.procps}/bin/pidof "hyprsunset" > /dev/null; then - pkill hyprsunset - OSD_TEXT="󰖔 Night Shift Off" - else - ${pkgs.hyprsunset}/bin/hyprsunset -t 4500 & - OSD_TEXT="󰖔 Night Shift On" - fi - ${updateOsd} - ''; - - focus-toggle = pkgs.writeShellScriptBin "focus-toggle" '' - if test -f "$XDG_RUNTIME_DIR/hypr-focus-mode"; then - rm "$XDG_RUNTIME_DIR/hypr-focus-mode" - OSD_TEXT="󰈈 Focus Off" - ${updateOsd} - ${pkgs.hyprland}/bin/hyprctl reload - ${pkgs.hyprland}/bin/hyprctl dispatch exec waybar - else - touch "$XDG_RUNTIME_DIR/hypr-focus-mode" - OSD_TEXT="󰈈 Focus On" - ${updateOsd} - ${pkgs.procps}/bin/pkill waybar || true - ${pkgs.hyprland}/bin/hyprctl keyword animations:enabled false - ${pkgs.hyprland}/bin/hyprctl keyword general:gaps_in 0 - ${pkgs.hyprland}/bin/hyprctl keyword general:gaps_out 0 - ${pkgs.hyprland}/bin/hyprctl keyword decoration:active_opacity 1 - ${pkgs.hyprland}/bin/hyprctl keyword decoration:inactive_opacity 1 - ${pkgs.hyprland}/bin/hyprctl keyword decoration:rounding 0 - fi - ''; - - dnd-toggle = pkgs.writeShellScriptBin "dnd-toggle" '' - state=$(${pkgs.swaynotificationcenter}/bin/swaync-client -d) - if [ "$state" = "true" ]; then - OSD_TEXT="󰂛 Do Not Disturb On" - else - OSD_TEXT="󰂚 Do Not Disturb Off" - fi - ${updateOsd} - ''; - - output-cycle = pkgs.writeShellScriptBin "output-cycle" '' - wpctl=${pkgs.wireplumber}/bin/wpctl - jq=${pkgs.jq}/bin/jq - pwdump=${pkgs.pipewire}/bin/pw-dump - - # Sink IDs in pw-dump order. - ids=($("$pwdump" | "$jq" -r '.[] | select(.info.props."media.class"=="Audio/Sink") | .id')) - n=''${#ids[@]} - [ "$n" -eq 0 ] && exit 0 - - cur=$("$wpctl" inspect @DEFAULT_AUDIO_SINK@ 2>/dev/null | sed -n 's/^id \([0-9]*\),.*/\1/p') - - next_index=0 - for i in "''${!ids[@]}"; do - if [ "''${ids[$i]}" = "$cur" ]; then - next_index=$(( (i + 1) % n )) - break - fi - done - next=''${ids[$next_index]} - - "$wpctl" set-default "$next" - desc=$("$pwdump" | "$jq" -r --argjson id "$next" '.[] | select(.id==$id) | .info.props."node.description"') - OSD_TEXT="󰓃 ''${desc:-Output}" - ${updateOsd} - ''; - - input-cycle = pkgs.writeShellScriptBin "input-cycle" '' - wpctl=${pkgs.wireplumber}/bin/wpctl - jq=${pkgs.jq}/bin/jq - pwdump=${pkgs.pipewire}/bin/pw-dump - - # Source IDs in pw-dump order. - ids=($("$pwdump" | "$jq" -r '.[] | select(.info.props."media.class"=="Audio/Source") | .id')) - n=''${#ids[@]} - [ "$n" -eq 0 ] && exit 0 - - cur=$("$wpctl" inspect @DEFAULT_AUDIO_SOURCE@ 2>/dev/null | sed -n 's/^id \([0-9]*\),.*/\1/p') - - next_index=0 - for i in "''${!ids[@]}"; do - if [ "''${ids[$i]}" = "$cur" ]; then - next_index=$(( (i + 1) % n )) - break - fi - done - next=''${ids[$next_index]} - - "$wpctl" set-default "$next" - desc=$("$pwdump" | "$jq" -r --argjson id "$next" '.[] | select(.id==$id) | .info.props."node.description"') - OSD_TEXT="󰍬 ''${desc:-Input}" - ${updateOsd} - ''; - - color-pick = pkgs.writeShellScriptBin "color-pick" '' - # hyprpicker -a already copies the color to the clipboard. - color=$(${pkgs.hyprpicker}/bin/hyprpicker -a 2>/dev/null) - if [ -n "$color" ]; then - OSD_TEXT="󰈊 $color" - else - OSD_TEXT="󰈊 Cancelled" - fi - ${updateOsd} - ''; - - screenshot-edit = pkgs.writeShellScriptBin "screenshot-edit" '' - ${pkgs.hyprshot}/bin/hyprshot -m region --raw 2>/dev/null \ - | ${pkgs.satty}/bin/satty --filename - - ''; - - record-toggle = pkgs.writeShellScriptBin "record-toggle" '' - if pgrep -x wf-recorder >/dev/null; then - # -INT lets wf-recorder finalize the file cleanly. - pkill -INT -x wf-recorder - OSD_TEXT="󰕧 Recording saved" - else - dir="$HOME/Videos" - mkdir -p "$dir" - file="$dir/rec-$(date +%Y%m%d-%H%M%S).mp4" - ${pkgs.wf-recorder}/bin/wf-recorder -f "$file" >/dev/null 2>&1 & - OSD_TEXT="󰑊 Recording…" - fi - ${updateOsd} - ''; - - power-cycle = pkgs.writeShellScriptBin "power-cycle" '' - ppd=${pkgs.power-profiles-daemon}/bin/powerprofilesctl - cur=$("$ppd" get) - case "$cur" in - power-saver) next=balanced; icon="󰾅" ;; - balanced) next=performance; icon="󰓅" ;; - performance) next=power-saver; icon="󰌪" ;; - *) next=balanced; icon="󰾅" ;; - esac - "$ppd" set "$next" - OSD_TEXT="$icon ''${next^}" - ${updateOsd} - ''; - - airplane-toggle = pkgs.writeShellScriptBin "airplane-toggle" '' - # Reuse nmcli + bluetoothctl (unprivileged) instead of rfkill. - on=false - nmcli radio wifi 2>/dev/null | grep -q enabled && on=true - bluetoothctl show 2>/dev/null | grep -q "Powered: yes" && on=true - if $on; then - nmcli radio wifi off 2>/dev/null - bluetoothctl power off >/dev/null 2>&1 || true - OSD_TEXT="󰀝 Airplane On" - else - nmcli radio wifi on 2>/dev/null - bluetoothctl power on >/dev/null 2>&1 || true - OSD_TEXT="󰀞 Airplane Off" - fi - ${updateOsd} - ''; - - clipboard-menu = pkgs.writeShellScriptBin "clipboard-menu" '' - list=$(${pkgs.cliphist}/bin/cliphist list) - selected=$(printf '%s\n' "$list" | cut -f2- | ${tofiMenu} --prompt-text "Clipboard: ") - [ -n "$selected" ] && printf '%s\n' "$list" \ - | awk -F'\t' -v s="$selected" '$2 == s {print; exit}' \ - | ${pkgs.cliphist}/bin/cliphist decode \ - | ${pkgs.wl-clipboard}/bin/wl-copy - ''; - - emoji-picker = pkgs.writeShellScriptBin "emoji-picker" '' - export PATH="${pkgs.wtype}/bin:${pkgs.wl-clipboard}/bin:$PATH" - export BEMOJI_PICKER_CMD="${tofiMenu} --prompt-text 'emoji: '" - # -t types the emoji (wtype), -c also copies it. - exec ${pkgs.bemoji}/bin/bemoji -t -c - ''; - - icon-picker = pkgs.writeShellScriptBin "icon-picker" '' - selected=$(${tofiMenu} --font "${config.stylix.fonts.monospace.name}" --prompt-text 'icon: ' < ${nerdFontIconList}) - [ -z "$selected" ] || icon=$(printf '%s\n' "$selected" | awk '{print $1}') - [ -n "''${icon:-}" ] || exit 0 - ${pkgs.wtype}/bin/wtype "$icon" - printf '%s' "$icon" | ${pkgs.wl-clipboard}/bin/wl-copy - ''; - - caffeine-toggle = pkgs.writeShellScriptBin "caffeine-toggle" '' - # Pause hypridle (stay awake) or resume it. - if systemctl --user is-active --quiet hypridle; then - systemctl --user stop hypridle - OSD_TEXT="󰅶 Keep Awake On" - else - systemctl --user start hypridle - OSD_TEXT="󰾫 Keep Awake Off" - fi - ${updateOsd} - ''; -} diff --git a/home/system/waybar/scripts/audio.nix b/home/system/waybar/scripts/audio.nix new file mode 100644 index 00000000..05cc7c9f --- /dev/null +++ b/home/system/waybar/scripts/audio.nix @@ -0,0 +1,74 @@ +{ + pkgs, + scripts, + ... +}: let + volGetText = '' + VOL_RAW=$(${pkgs.wireplumber}/bin/wpctl get-volume @DEFAULT_SINK@) + VOL=$(printf '%s' "$VOL_RAW" | awk '{printf "%d", $2*100}') + if printf '%s' "$VOL_RAW" | grep -q MUTED; then + OSD_TEXT="󰝟 $VOL%" + elif [ "$VOL" -lt 33 ]; then + OSD_TEXT="󰕿 $VOL%" + elif [ "$VOL" -lt 66 ]; then + OSD_TEXT="󰖀 $VOL%" + else + OSD_TEXT="󰕾 $VOL%" + fi + ''; + + # Resolve $src: the default source, otherwise the first available source. + # Some machines have no default audio source (@DEFAULT_AUDIO_SOURCE@ unresolved). + micSource = '' + src=$(${pkgs.wireplumber}/bin/wpctl inspect @DEFAULT_AUDIO_SOURCE@ 2>/dev/null | sed -n 's/^id \([0-9]*\),.*/\1/p') + if [ -z "$src" ]; then + src=$(${pkgs.pipewire}/bin/pw-dump | ${pkgs.jq}/bin/jq -r \ + '[.[] | select(.info.props."media.class"=="Audio/Source") | .id] | .[0] // empty') + fi + ''; + + updateOsd = '' + ${scripts.waybar-osd}/bin/waybar-osd "$OSD_TEXT" + ''; +in { + scripts.vol-up = pkgs.writeShellScriptBin "vol-up" '' + ${pkgs.wireplumber}/bin/wpctl set-volume @DEFAULT_SINK@ 5%+ --limit 1.0 + ${volGetText} + ${updateOsd} + ''; + + scripts.vol-down = pkgs.writeShellScriptBin "vol-down" '' + ${pkgs.wireplumber}/bin/wpctl set-volume @DEFAULT_SINK@ 5%- + ${volGetText} + ${updateOsd} + ''; + + scripts.vol-mute = pkgs.writeShellScriptBin "vol-mute" '' + ${pkgs.wireplumber}/bin/wpctl set-mute @DEFAULT_SINK@ toggle + ${volGetText} + ${updateOsd} + ''; + + scripts.mic-mute = pkgs.writeShellScriptBin "mic-mute" '' + wpctl=${pkgs.wireplumber}/bin/wpctl + ${micSource} + [ -z "$src" ] && exit 0 + + "$wpctl" set-mute "$src" toggle + if "$wpctl" get-volume "$src" | grep -q MUTED; then + OSD_TEXT="󰍭 Muted" + else + OSD_TEXT="󰍬 Live" + fi + ${updateOsd} + ''; + + scripts.mic-status = pkgs.writeShellScriptBin "mic-status" '' + ${micSource} + if [ -n "$src" ] && ${pkgs.wireplumber}/bin/wpctl get-volume "$src" | grep -q MUTED; then + echo true + else + echo false + fi + ''; +} diff --git a/home/system/waybar/scripts/bluetooth.nix b/home/system/waybar/scripts/bluetooth.nix new file mode 100644 index 00000000..1e8d03ff --- /dev/null +++ b/home/system/waybar/scripts/bluetooth.nix @@ -0,0 +1,50 @@ +{ + pkgs, + scripts, + ... +}: let + updateOsd = '' + ${scripts.waybar-osd}/bin/waybar-osd "$OSD_TEXT" + ''; +in { + scripts.bluetoothScript = pkgs.writeShellScript "waybar-bluetooth" '' + jq=${pkgs.jq}/bin/jq + nl=$'\n' + # bluetoothctl hangs without a controller by default → always bounded by timeout. + bt() { timeout 3 ${pkgs.bluez}/bin/bluetoothctl "$@" 2>/dev/null; } + + powered=$(bt show | awk '/Powered:/ { print $2; exit }') + if [ "$powered" != "yes" ]; then + "$jq" -cn '{ text: "󰂲", class: "off", tooltip: "Bluetooth off" }' + exit 0 + fi + + tip="" + add_tip() { tip="''${tip:+$tip$nl}$1"; } + + count=0 + for mac in $(bt devices Connected | awk '{ print $2 }'); do + count=$((count + 1)) + info=$(bt info "$mac") + name=$(printf '%s' "$info" | sed -n 's/^[[:space:]]*Name: //p' | head -1) + [ -z "$name" ] && name="$mac" + batt=$(printf '%s' "$info" | sed -n 's/.*Battery Percentage:.*(\([0-9][0-9]*\)).*/\1/p' | head -1) + add_tip "󰂱 $name''${batt:+ · $batt%}" + done + + if [ "$count" -gt 0 ]; then + "$jq" -cn --arg tooltip "$tip" '{ text: "󰂰", class: "connected", tooltip: $tooltip }' + else + "$jq" -cn '{ text: "󰂰", class: "on", tooltip: "Bluetooth on" }' + fi + ''; + + scripts.bluetooth-toggle = pkgs.writeShellScriptBin "bluetooth-toggle" '' + if ${pkgs.bluez}/bin/bluetoothctl show | grep -q "Powered: yes"; then + ${pkgs.bluez}/bin/bluetoothctl power off + else + ${pkgs.bluez}/bin/bluetoothctl power on + fi + ${updateOsd} + ''; +} diff --git a/home/system/waybar/scripts/brightness.nix b/home/system/waybar/scripts/brightness.nix new file mode 100644 index 00000000..0c014701 --- /dev/null +++ b/home/system/waybar/scripts/brightness.nix @@ -0,0 +1,32 @@ +{ + pkgs, + scripts, + ... +}: let + brightGetText = '' + BRIGHT=$(${pkgs.brightnessctl}/bin/brightnessctl -m | awk -F, '{print int($5)}') + if [ "$BRIGHT" -lt 33 ]; then + OSD_TEXT="󰃞 $BRIGHT%" + elif [ "$BRIGHT" -lt 66 ]; then + OSD_TEXT="󰃟 $BRIGHT%" + else + OSD_TEXT="󰃠 $BRIGHT%" + fi + ''; + + updateOsd = '' + ${scripts.waybar-osd}/bin/waybar-osd "$OSD_TEXT" + ''; +in { + scripts.bright-up = pkgs.writeShellScriptBin "bright-up" '' + ${pkgs.brightnessctl}/bin/brightnessctl set 5%+ + ${brightGetText} + ${updateOsd} + ''; + + scripts.bright-down = pkgs.writeShellScriptBin "bright-down" '' + ${pkgs.brightnessctl}/bin/brightnessctl set 5%- + ${brightGetText} + ${updateOsd} + ''; +} diff --git a/home/system/waybar/scripts/default.nix b/home/system/waybar/scripts/default.nix new file mode 100644 index 00000000..dcc0b74f --- /dev/null +++ b/home/system/waybar/scripts/default.nix @@ -0,0 +1,11 @@ +{ + imports = [ + ./osd.nix + ./bluetooth.nix + ./network.nix + ./audio.nix + ./brightness.nix + ./devices.nix + ./misc.nix + ]; +} diff --git a/home/system/waybar/scripts/devices.nix b/home/system/waybar/scripts/devices.nix new file mode 100644 index 00000000..4b9368de --- /dev/null +++ b/home/system/waybar/scripts/devices.nix @@ -0,0 +1,63 @@ +{ + pkgs, + scripts, + ... +}: let + updateOsd = '' + ${scripts.waybar-osd}/bin/waybar-osd "$OSD_TEXT" + ''; +in { + scripts.output-cycle = pkgs.writeShellScriptBin "output-cycle" '' + wpctl=${pkgs.wireplumber}/bin/wpctl + jq=${pkgs.jq}/bin/jq + pwdump=${pkgs.pipewire}/bin/pw-dump + + # Sink IDs in pw-dump order. + ids=($("$pwdump" | "$jq" -r '.[] | select(.info.props."media.class"=="Audio/Sink") | .id')) + n=''${#ids[@]} + [ "$n" -eq 0 ] && exit 0 + + cur=$("$wpctl" inspect @DEFAULT_AUDIO_SINK@ 2>/dev/null | sed -n 's/^id \([0-9]*\),.*/\1/p') + + next_index=0 + for i in "''${!ids[@]}"; do + if [ "''${ids[$i]}" = "$cur" ]; then + next_index=$(( (i + 1) % n )) + break + fi + done + next=''${ids[$next_index]} + + "$wpctl" set-default "$next" + desc=$("$pwdump" | "$jq" -r --argjson id "$next" '.[] | select(.id==$id) | .info.props."node.description"') + OSD_TEXT="󰓃 ''${desc:-Output}" + ${updateOsd} + ''; + + scripts.input-cycle = pkgs.writeShellScriptBin "input-cycle" '' + wpctl=${pkgs.wireplumber}/bin/wpctl + jq=${pkgs.jq}/bin/jq + pwdump=${pkgs.pipewire}/bin/pw-dump + + # Source IDs in pw-dump order. + ids=($("$pwdump" | "$jq" -r '.[] | select(.info.props."media.class"=="Audio/Source") | .id')) + n=''${#ids[@]} + [ "$n" -eq 0 ] && exit 0 + + cur=$("$wpctl" inspect @DEFAULT_AUDIO_SOURCE@ 2>/dev/null | sed -n 's/^id \([0-9]*\),.*/\1/p') + + next_index=0 + for i in "''${!ids[@]}"; do + if [ "''${ids[$i]}" = "$cur" ]; then + next_index=$(( (i + 1) % n )) + break + fi + done + next=''${ids[$next_index]} + + "$wpctl" set-default "$next" + desc=$("$pwdump" | "$jq" -r --argjson id "$next" '.[] | select(.id==$id) | .info.props."node.description"') + OSD_TEXT="󰍬 ''${desc:-Input}" + ${updateOsd} + ''; +} diff --git a/home/system/waybar/scripts/misc.nix b/home/system/waybar/scripts/misc.nix new file mode 100644 index 00000000..9a8f4f6a --- /dev/null +++ b/home/system/waybar/scripts/misc.nix @@ -0,0 +1,65 @@ +{ + pkgs, + scripts, + ... +}: let + updateOsd = '' + ${scripts.waybar-osd}/bin/waybar-osd "$OSD_TEXT" + ''; +in { + scripts.waybar-toggle = pkgs.writeShellScriptBin "waybar-toggle" '' + if pidof waybar > /dev/null; then + pkill waybar + else + hyprctl dispatch exec waybar + fi + ''; + + scripts.color-pick = pkgs.writeShellScriptBin "color-pick" '' + # hyprpicker -a already copies the color to the clipboard. + color=$(${pkgs.hyprpicker}/bin/hyprpicker -a 2>/dev/null) + if [ -n "$color" ]; then + OSD_TEXT="󰈊 $color" + else + OSD_TEXT="󰈊 Cancelled" + fi + ${updateOsd} + ''; + + scripts.screenshot-edit = pkgs.writeShellScriptBin "screenshot-edit" '' + ${pkgs.hyprshot}/bin/hyprshot -m region --raw 2>/dev/null \ + | ${pkgs.satty}/bin/satty --filename - + ''; + + scripts.record-toggle = pkgs.writeShellScriptBin "record-toggle" '' + if pgrep -x wf-recorder >/dev/null; then + # -INT lets wf-recorder finalize the file cleanly. + pkill -INT -x wf-recorder + OSD_TEXT="󰕧 Recording saved" + else + dir="$HOME/Videos" + mkdir -p "$dir" + file="$dir/rec-$(date +%Y%m%d-%H%M%S).mp4" + ${pkgs.wf-recorder}/bin/wf-recorder -f "$file" >/dev/null 2>&1 & + OSD_TEXT="󰑊 Recording…" + fi + ${updateOsd} + ''; + + scripts.airplane-toggle = pkgs.writeShellScriptBin "airplane-toggle" '' + # Reuse nmcli + bluetoothctl (unprivileged) instead of rfkill. + on=false + nmcli radio wifi 2>/dev/null | grep -q enabled && on=true + bluetoothctl show 2>/dev/null | grep -q "Powered: yes" && on=true + if $on; then + nmcli radio wifi off 2>/dev/null + bluetoothctl power off >/dev/null 2>&1 || true + OSD_TEXT="󰀝 Airplane On" + else + nmcli radio wifi on 2>/dev/null + bluetoothctl power on >/dev/null 2>&1 || true + OSD_TEXT="󰀞 Airplane Off" + fi + ${updateOsd} + ''; +} diff --git a/home/system/waybar/scripts/network.nix b/home/system/waybar/scripts/network.nix new file mode 100644 index 00000000..0ede8dce --- /dev/null +++ b/home/system/waybar/scripts/network.nix @@ -0,0 +1,77 @@ +{ + pkgs, + scripts, + ... +}: let + updateOsd = '' + ${scripts.waybar-osd}/bin/waybar-osd "$OSD_TEXT" + ''; +in { + scripts.networkScript = pkgs.writeShellScript "waybar-network" '' + nmcli=${pkgs.networkmanager}/bin/nmcli + ip=${pkgs.iproute2}/bin/ip + jq=${pkgs.jq}/bin/jq + nl=$'\n' + + text="" + tip="" + class="disconnected" + add_seg() { text="''${text:+$text }$1"; } + add_tip() { tip="''${tip:+$tip$nl}$1"; } + + # ── Ethernet ──────────────────────────────────────────────── + eth=$("$nmcli" -t -f DEVICE,TYPE,STATE device status 2>/dev/null \ + | awk -F: '$2 == "ethernet" && $3 == "connected" { print $1; exit }') + if [ -n "$eth" ]; then + eth_ip=$("$ip" -4 -br addr show "$eth" 2>/dev/null | awk '{ print $3 }' | cut -d/ -f1) + add_seg "󰛳" + class="ethernet" + add_tip "󰛳 Ethernet''${eth_ip:+ · $eth_ip}" + fi + + # ── Wi-Fi ─────────────────────────────────────────────────── + wifi=$("$nmcli" -t -f ACTIVE,SSID,SIGNAL device wifi 2>/dev/null | grep -m1 '^yes:') + if [ -n "$wifi" ]; then + ssid=$(printf '%s' "$wifi" | cut -d: -f2) + signal=$(printf '%s' "$wifi" | cut -d: -f3) + if [ "''${signal:-0}" -ge 80 ]; then icon="󰤨" + elif [ "''${signal:-0}" -ge 60 ]; then icon="󰤥" + elif [ "''${signal:-0}" -ge 40 ]; then icon="󰤢" + elif [ "''${signal:-0}" -ge 20 ]; then icon="󰤟" + else icon="󰤯" + fi + add_seg "$icon" + [ "$class" = "disconnected" ] && class="wifi" + add_tip "$icon ''${ssid:-Wi-Fi}''${signal:+ · $signal%}" + fi + + # ── VPN (nmcli, fallback interfaces) ──────────────────────── + vpn=$("$nmcli" -t -f TYPE,NAME connection show --active 2>/dev/null \ + | awk -F: '$1 == "vpn" || $1 == "wireguard" { print $2; exit }') + if [ -z "$vpn" ]; then + vpn=$("$ip" -br link show 2>/dev/null \ + | awk '($2 == "UP" || $2 == "UNKNOWN") && $1 ~ /^(tun|wg|proton|ppp)/ { sub(/@.*/, "", $1); print $1; exit }') + fi + if [ -n "$vpn" ]; then + add_seg "󰦝" + add_tip "󰦝 VPN · $vpn" + fi + + if [ -z "$text" ]; then + text="󰤭" + tip="Disconnected" + fi + + "$jq" -cn --arg text "$text" --arg class "$class" --arg tooltip "$tip" \ + '{ text: $text, class: $class, tooltip: $tooltip }' + ''; + + scripts.wifi-toggle = pkgs.writeShellScriptBin "wifi-toggle" '' + if ${pkgs.networkmanager}/bin/nmcli radio wifi | grep -q enabled; then + ${pkgs.networkmanager}/bin/nmcli radio wifi off + else + ${pkgs.networkmanager}/bin/nmcli radio wifi on + fi + ${updateOsd} + ''; +} diff --git a/home/system/waybar/scripts/osd.nix b/home/system/waybar/scripts/osd.nix new file mode 100644 index 00000000..447ee299 --- /dev/null +++ b/home/system/waybar/scripts/osd.nix @@ -0,0 +1,27 @@ +{pkgs, ...}: { + scripts.waybar-osd = pkgs.writeShellApplication { + name = "waybar-osd"; + runtimeInputs = with pkgs; [procps coreutils]; + text = '' + printf '%s' "$1" > "$XDG_RUNTIME_DIR/waybar-osd" + pkill -f -RTMIN+8 '^waybar$' 2>/dev/null || true + ''; + }; + + scripts.waybar-osd-status = pkgs.writeShellApplication { + name = "waybar-osd-status"; + runtimeInputs = with pkgs; [coreutils]; + text = '' + file="$XDG_RUNTIME_DIR/waybar-osd" + [ -f "$file" ] || exit 1 + mtime=$(stat -c %Y "$file" 2>/dev/null) || exit 1 + age=$(( $(date +%s) - mtime )) + if [ "$age" -ge 3 ]; then + rm -f "$file" + exit 1 + fi + ''; + }; + + _module.args.osdPath = "$XDG_RUNTIME_DIR/waybar-osd"; +} diff --git a/home/system/waybar/settings.nix b/home/system/waybar/settings.nix index 392baa95..64bd99df 100644 --- a/home/system/waybar/settings.nix +++ b/home/system/waybar/settings.nix @@ -2,11 +2,6 @@ config, pkgs, osdPath, - networkScript, - bluetoothScript, - caffeineToggleScript, - osdStatusScript, - nightshiftToggleScript, ... }: let gaps-out = config.theme.gaps-out; @@ -18,9 +13,7 @@ in { position = "top"; height = config.theme.bar-height; margin = "${toString gaps-out} ${toString gaps-out} 0"; - modules-center = ["custom/osd" "custom/osd-sep" "clock" "tray" "hyprland/workspaces" "custom/network" "custom/bluetooth" "battery" "group/drawer"]; - - # ── Modules ───────────────────────────────────────────────────────── + modules-center = ["custom/osd" "custom/osd-sep" "clock" "tray" "hyprland/workspaces" "custom/network" "custom/bluetooth" "battery" "pulseaudio" "custom/nightshift" "custom/caffeine"]; "hyprland/workspaces" = { format = "{id}"; @@ -55,7 +48,7 @@ in { exec-if = "! systemctl --user is-active --quiet hypridle"; format = "{}"; interval = 5; - on-click = "${caffeineToggleScript}/bin/caffeine-toggle"; + on-click = "${config.scripts.caffeine-toggle}/bin/caffeine-toggle"; tooltip = false; }; @@ -64,12 +57,12 @@ in { exec-if = "${pkgs.procps}/bin/pgrep -x hyprsunset"; format = "{}"; interval = 5; - on-click = "${nightshiftToggleScript}/bin/nightshift-toggle"; + on-click = "${config.scripts.nightshift-toggle}/bin/nightshift-toggle"; tooltip = false; }; "custom/bluetooth" = { - exec = "${bluetoothScript}"; + exec = "${config.scripts.bluetoothScript}"; exec-if = "${pkgs.bluez}/bin/bluetoothctl list 2>/dev/null | grep -q Controller"; return-type = "json"; interval = 5; @@ -78,7 +71,7 @@ in { "custom/osd" = { exec = "cat ${osdPath}"; - exec-if = "${osdStatusScript}/bin/waybar-osd-status"; + exec-if = "${config.scripts.waybar-osd-status}/bin/waybar-osd-status"; signal = 8; interval = 1; format = "{}"; @@ -86,7 +79,7 @@ in { "custom/osd-sep" = { exec = "echo '|'"; - exec-if = "${osdStatusScript}/bin/waybar-osd-status"; + exec-if = "${config.scripts.waybar-osd-status}/bin/waybar-osd-status"; signal = 8; interval = 1; format = "{}"; @@ -122,7 +115,7 @@ in { }; "custom/network" = { - exec = "${networkScript}"; + exec = "${config.scripts.networkScript}"; return-type = "json"; interval = 10; on-click = "${pkgs.ghostty}/bin/ghostty +new-window -e ${pkgs.nur.repos.anotherhadi.settuings}/bin/settuings --page network"; diff --git a/home/programs/tui/elio/default.nix b/home/tui/elio/default.nix similarity index 92% rename from home/programs/tui/elio/default.nix rename to home/tui/elio/default.nix index b1a43a94..564f5e84 100644 --- a/home/programs/tui/elio/default.nix +++ b/home/tui/elio/default.nix @@ -1,3 +1,4 @@ +# Elio is a TUI file explorer { pkgs, config, @@ -5,16 +6,12 @@ }: let c = config.lib.stylix.colors; # TODO: Waiting for a version in nixpkgs - version = "1.11.2"; + version = "1.12.0"; sources = { "x86_64-linux" = { url = "https://github.com/elio-fm/elio/releases/download/v${version}/elio-${version}-x86_64-unknown-linux-gnu.tar.gz"; hash = "sha256-9cW/xUA9p0LEYI3/j4MGPVZvcyJpV1JYKYBuHur4sTM="; }; - "aarch64-linux" = { - url = "https://github.com/elio-fm/elio/releases/download/v${version}/elio-${version}-aarch64-unknown-linux-gnu.tar.gz"; - hash = "sha256-zg141Dp+jHwAqzoaCNvOoC7ZFeAX+cO8HZF5W7wz1Qs="; - }; }; source = sources.${pkgs.stdenv.hostPlatform.system} @@ -55,7 +52,12 @@ }; }; in { - home.packages = [elio]; + home.packages = [ + elio + pkgs.poppler-utils # PDF previews + pkgs.ffmpeg # media metadata and thumbnails + pkgs.resvg # SVG previews + ]; xdg.desktopEntries.elio = { name = "elio"; diff --git a/home/programs/tui/ghostty/default.nix b/home/tui/ghostty/default.nix similarity index 100% rename from home/programs/tui/ghostty/default.nix rename to home/tui/ghostty/default.nix diff --git a/home/tui/git/default.nix b/home/tui/git/default.nix new file mode 100644 index 00000000..19dec2a3 --- /dev/null +++ b/home/tui/git/default.nix @@ -0,0 +1,64 @@ +# Git configuration +{ + config, + lib, + ... +}: let + username = config.var.git.username; + email = config.var.git.email; +in { + imports = [./lazygit.nix]; + programs = { + gh.enable = true; + git = { + enable = true; + ignores = [ + ".cache/" + ".DS_Store" + ".idea/" + "*.swp" + "*.elc" + "auto-save-list" + ".direnv/" + "node_modules" + "result" + "result-*" + ".superpowers/" + ".claude/" + "docs/superpowers/" + ]; + settings = { + user.name = username; + user.email = email; + init.defaultBranch = "main"; + pull.rebase = "true"; + push.autoSetupRemote = true; + color.ui = "1"; + alias = { + co = "checkout"; + fuck = "commit --amend -m"; + c = "commit -m"; + ca = "commit -am"; + forgor = "commit --amend --no-edit"; + graph = "log --all --decorate --graph --oneline"; + oops = "checkout --"; + l = "log"; + r = "rebase"; + s = "status --short"; + ss = "status"; + d = "diff"; + ps = "!git push origin $(git rev-parse --abbrev-ref HEAD)"; + pl = "!git pull origin $(git rev-parse --abbrev-ref HEAD)"; + st = "status"; + br = "branch"; + hist = ''log --pretty=format:"%Cgreen%h %Creset%cd %Cblue[%cn] %Creset%s%C(yellow)%d%C(reset)" --graph --date=relative --decorate --all''; + llog = ''log --graph --name-status --pretty=format:"%C(red)%h %C(reset)(%cd) %C(green)%an %Creset%s %C(yellow)%d%Creset" --date=relative''; + }; + }; + }; + }; + + home.persistence."/persist" = lib.mkIf (config.var.impermanenceEnabled or false) { + directories = [".config/gh"]; + }; +} diff --git a/home/programs/tui/git/lazygit.nix b/home/tui/git/lazygit.nix similarity index 100% rename from home/programs/tui/git/lazygit.nix rename to home/tui/git/lazygit.nix diff --git a/home/programs/tui/git/signing.nix b/home/tui/git/signing.nix similarity index 81% rename from home/programs/tui/git/signing.nix rename to home/tui/git/signing.nix index 4b2ea9be..ec2d76ca 100644 --- a/home/programs/tui/git/signing.nix +++ b/home/tui/git/signing.nix @@ -1,10 +1,10 @@ # This file is used to sign git commits using an SSH key. { # CHANGEME: change this to your own SSH key. + # ~/.ssh/key.pub itself is managed by sops (see hosts/laptop/secrets/default.nix: signing-pub-key). home.file.".ssh/allowed_signers".text = "* ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIINhWby7lUUXQNKbRu9/UOrGjWDf3fvoAwGHomWv/+lL"; programs.git = { - signing.format = "openpgp"; settings = { commit.gpgsign = true; gpg.ssh.allowedSignersFile = "~/.ssh/allowed_signers"; diff --git a/home/programs/tui/ilovetui/default.nix b/home/tui/ilovetui/default.nix similarity index 100% rename from home/programs/tui/ilovetui/default.nix rename to home/tui/ilovetui/default.nix diff --git a/home/tui/kew/default.nix b/home/tui/kew/default.nix new file mode 100644 index 00000000..8423e941 --- /dev/null +++ b/home/tui/kew/default.nix @@ -0,0 +1,45 @@ +# Kew is a TUI audio player +{ + pkgs, + lib, + config, + ... +}: let + kewLauncher = pkgs.writeShellScript "kew-launcher" '' + if [ -n "$1" ]; then + exec ${pkgs.kew}/bin/kew play "$1" + else + exec ${pkgs.kew}/bin/kew + fi + ''; +in { + home.packages = with pkgs; [ + kew + ]; + + home.persistence."/persist" = lib.mkIf (config.var.impermanenceEnabled or false) { + directories = [ + ".config/kew" + ]; + }; + + xdg.desktopEntries.kew = { + name = "Music Player"; + exec = "${pkgs.ghostty}/bin/ghostty --window-padding-x=0 --window-padding-y=0 -e ${kewLauncher} %f"; + comment = "Play music from the terminal"; + categories = ["Audio" "Music"]; + terminal = false; + mimeType = [ + "audio/aac" + "audio/mpeg" + "audio/ogg" + "audio/opus" + "audio/vnd.wave" + "audio/webm" + "audio/x-matroska" + "audio/flac" + "audio/mp4" + ]; + settings.Keywords = "lofi;player;music;"; + }; +} diff --git a/home/tui/misc/btop/default.nix b/home/tui/misc/btop/default.nix new file mode 100644 index 00000000..a9c69701 --- /dev/null +++ b/home/tui/misc/btop/default.nix @@ -0,0 +1,21 @@ +{pkgs, ...}: let + btopPackage = pkgs.btop.override {cudaSupport = true;}; +in { + programs.btop = { + enable = true; + package = btopPackage; + settings = { + vim_keys = true; + shown_boxes = "cpu mem net proc gpu0"; + }; + }; + + xdg.desktopEntries.btop = { + name = "btop++"; + exec = "${pkgs.ghostty}/bin/ghostty +new-window -e ${btopPackage}/bin/btop"; + comment = "Ressources monitor (btop)"; + categories = ["Settings"]; + terminal = false; + settings.Keywords = "ressource;ressources;btop;usage;monitoring;cpu;gpu;memory"; + }; +} diff --git a/home/tui/misc/cava/default.nix b/home/tui/misc/cava/default.nix new file mode 100644 index 00000000..96878884 --- /dev/null +++ b/home/tui/misc/cava/default.nix @@ -0,0 +1,5 @@ +{ + programs = { + cava.enable = true; + }; +} diff --git a/home/programs/group/cybersecurity.nix b/home/tui/misc/cybersecurity/default.nix similarity index 86% rename from home/programs/group/cybersecurity.nix rename to home/tui/misc/cybersecurity/default.nix index 5619ba71..b2fb347b 100644 --- a/home/programs/group/cybersecurity.nix +++ b/home/tui/misc/cybersecurity/default.nix @@ -5,16 +5,10 @@ inputs, ... }: { - home.packages = import ./cybersecurity-packages.nix { + home.packages = import ./pkgs.nix { inherit pkgs; }; - systemd.user.tmpfiles.rules = [ - "d %h/Cyber/tmp 0755 - - -" - "d %h/Cyber/wordlists 0755 - - -" - "d %h/Cyber/wordlists/rules 0755 - - -" - ]; - home.file = { "Cyber/wordlists/seclists".source = pkgs.fetchFromGitHub { owner = "danielmiessler"; @@ -43,6 +37,7 @@ hash = "sha256-T0XkMHJZQiy63/j25nGTkaiDFjc+blmgEVGTAFgVylU="; }; + # Open source list of default credentials ".cache/default-creds".source = inputs.default-creds; }; diff --git a/home/programs/group/cybersecurity-packages.nix b/home/tui/misc/cybersecurity/pkgs.nix similarity index 100% rename from home/programs/group/cybersecurity-packages.nix rename to home/tui/misc/cybersecurity/pkgs.nix diff --git a/home/tui/misc/default.nix b/home/tui/misc/default.nix new file mode 100644 index 00000000..e772c5a8 --- /dev/null +++ b/home/tui/misc/default.nix @@ -0,0 +1,6 @@ +{lib, ...}: let + utils = import ../../lib/utils.nix {inherit lib;}; +in { + imports = + utils.importAll ./.; +} diff --git a/home/programs/group/dev.nix b/home/tui/misc/dev/default.nix similarity index 100% rename from home/programs/group/dev.nix rename to home/tui/misc/dev/default.nix diff --git a/home/tui/misc/eilmeldung/default.nix b/home/tui/misc/eilmeldung/default.nix new file mode 100644 index 00000000..e91b2b26 --- /dev/null +++ b/home/tui/misc/eilmeldung/default.nix @@ -0,0 +1,25 @@ +# Feature-rich TUI RSS reader based on the news-flash library +{ + config, + lib, + pkgs, + pkgs-unstable, + ... +}: { + home.packages = [ + pkgs-unstable.eilmeldung + ]; + + home.persistence."/persist" = lib.mkIf (config.var.impermanenceEnabled or false) { + directories = [".config/eilmeldung"]; + }; + + xdg.desktopEntries.eilmeldung = { + name = "eilmeldung"; + exec = "${pkgs.ghostty}/bin/ghostty +new-window -e ${pkgs-unstable.eilmeldung}/bin/eilmeldung"; + comment = "Feature-rich TUI RSS reader"; + categories = ["Network" "ConsoleOnly"]; + terminal = false; + settings.Keywords = "rss;feed;news;reader"; + }; +} diff --git a/home/tui/misc/monitui/default.nix b/home/tui/misc/monitui/default.nix new file mode 100644 index 00000000..76290f0e --- /dev/null +++ b/home/tui/misc/monitui/default.nix @@ -0,0 +1,15 @@ +# Monitui allows you to edit hyprland's monitor configuration +{pkgs, ...}: { + home.packages = [ + pkgs.nur.repos.anotherhadi.monitui + ]; + + xdg.desktopEntries.monitui = { + name = "monitui"; + exec = "${pkgs.ghostty}/bin/ghostty +new-window -e ${pkgs.nur.repos.anotherhadi.monitui}/bin/monitui"; + comment = "Delightfully minimal TUI for wrangling Hyprland monitors"; + categories = ["Settings" "HardwareSettings"]; + terminal = false; + settings.Keywords = "hyprland;monitor;display;screen;resolution"; + }; +} diff --git a/home/programs/tui/navi/default.nix b/home/tui/misc/navi/default.nix similarity index 100% rename from home/programs/tui/navi/default.nix rename to home/tui/misc/navi/default.nix diff --git a/home/programs/tui/nix-utils/default.nix b/home/tui/misc/nix-utils/default.nix similarity index 100% rename from home/programs/tui/nix-utils/default.nix rename to home/tui/misc/nix-utils/default.nix diff --git a/home/tui/misc/usbguard-tui/default.nix b/home/tui/misc/usbguard-tui/default.nix new file mode 100644 index 00000000..5c2fe678 --- /dev/null +++ b/home/tui/misc/usbguard-tui/default.nix @@ -0,0 +1,15 @@ +# TUI for managing USBGuard rules +{pkgs, ...}: { + home.packages = [ + pkgs.nur.repos.anotherhadi.usbguard-tui + ]; + + xdg.desktopEntries.usbguard-tui = { + name = "USBGuard TUI"; + exec = "${pkgs.ghostty}/bin/ghostty +new-window -e ${pkgs.polkit}/bin/pkexec ${pkgs.nur.repos.anotherhadi.usbguard-tui}/bin/usbguard-tui"; + comment = "Manage USBGuard rules"; + categories = ["Settings"]; + terminal = false; + settings.Keywords = "usb;usbguard;security;devices;rules"; + }; +} diff --git a/home/programs/tui/nixy/default.nix b/home/tui/nixy/default.nix similarity index 100% rename from home/programs/tui/nixy/default.nix rename to home/tui/nixy/default.nix diff --git a/home/programs/tui/nixy/flake.nix b/home/tui/nixy/flake.nix similarity index 100% rename from home/programs/tui/nixy/flake.nix rename to home/tui/nixy/flake.nix diff --git a/home/programs/tui/nixy/package.nix b/home/tui/nixy/package.nix similarity index 100% rename from home/programs/tui/nixy/package.nix rename to home/tui/nixy/package.nix diff --git a/home/programs/tui/pkgs.nix b/home/tui/pkgs/default.nix similarity index 67% rename from home/programs/tui/pkgs.nix rename to home/tui/pkgs/default.nix index c3b77fcb..80482447 100644 --- a/home/programs/tui/pkgs.nix +++ b/home/tui/pkgs/default.nix @@ -8,31 +8,24 @@ home.packages = with pkgs; [ # I love TUIs caligula # User-friendly, lightweight TUI for disk imaging (ISO, USB BOOT) - tealdeer # Fast tldr client sttr # A minimalist CyberChef-like, cross-platform CLI app for performing various operations on strings slides # A terminal-based presentation tool that allows you to create and deliver presentations directly from the command line - pom # Pomodoro timer in your terminal tabiew # A terminal-based CSV viewer and manipulator jless # A pager for JSON - pkgs.nur.repos.anotherhadi.usbguard-tui # TUI for managing USBGuard rules - pkgs.nur.repos.anotherhadi.settuings # Terminal based settings (wifi, bluetooth, audio, ...) - pkgs.nur.repos.anotherhadi.fztea # Flipper Zero from the terminal - pkgs.nur.repos.anotherhadi.monitui # Edit hyprland's monitor configuration - pkgs.nur.repos.anotherhadi.proton-vpn-tui dua # Tool to conveniently learn about the disk usage of directories mcat # Cat command for documents / images / videos and more lazyjournal vhs # Create GIF from the command-line - andcli # 2FA for your shell, waiting for the support of Proton AUTH in the andcli nixpkgs unstable version + pkgs.nur.repos.anotherhadi.settuings # Terminal based settings (wifi, bluetooth, audio, ...) + pkgs.nur.repos.anotherhadi.fztea # Flipper Zero from the terminal + pkgs-unstable.pomo # Pomodoro timer in your terminal httpie # Command-line HTTP client, a user-friendly cURL replacement - gh # GitHub figlet # Transform text into ASCII art pastel # Command-line tool to generate, analyze, convert and manipulate colors imagemagick # Image manipulation tool chafa # Image to ANSI/Unicode converter and more. - proton-vpn-cli - pkgs-unstable.eilmeldung + pkgs-unstable.yt-dlp # Just cool tty-solitaire @@ -43,10 +36,5 @@ cmatrix fastfetch smassh # typing test, 10fastfinger like - minesweep-rs # Mine sweeper ]; - - home.persistence."/persist" = lib.mkIf (config.var.impermanenceEnabled or false) { - directories = [".config/gh" ".config/gh-dash"]; - }; } diff --git a/home/tui/proton/default.nix b/home/tui/proton/default.nix new file mode 100644 index 00000000..051d0d7a --- /dev/null +++ b/home/tui/proton/default.nix @@ -0,0 +1,8 @@ +{ + # TODO: proton-pass-agent ? + imports = [ + ./proton-auth.nix + ./proton-calendar.nix + ./proton-vpn.nix + ]; +} diff --git a/home/tui/proton/proton-auth.nix b/home/tui/proton/proton-auth.nix new file mode 100644 index 00000000..557d693f --- /dev/null +++ b/home/tui/proton/proton-auth.nix @@ -0,0 +1,26 @@ +{ + config, + lib, + pkgs, + pkgs-unstable, + ... +}: { + home.packages = [ + pkgs-unstable.andcli # 2FA TUI for your shell + ]; + + home.persistence."/persist" = lib.mkIf (config.var.impermanenceEnabled or false) { + directories = [".config/andcli"]; + }; + + programs.zsh.shellAliases."andcli" = "${pkgs-unstable.andcli}/bin/andcli ~/.cache/protonauth.json.txt --type protonauth"; + + xdg.desktopEntries.andcli = { + name = "andcli"; + exec = "${pkgs.ghostty}/bin/ghostty +new-window -e ${pkgs-unstable.andcli}/bin/andcli ${config.home.homeDirectory}/.cache/protonauth.json.txt --type protonauth"; + comment = "2FA TUI for your shell"; + categories = ["Utility" "Security" "ConsoleOnly"]; + terminal = false; + settings.Keywords = "2fa;otp;totp;authenticator;security"; + }; +} diff --git a/home/tui/proton/proton-vpn.nix b/home/tui/proton/proton-vpn.nix new file mode 100644 index 00000000..ea9d5873 --- /dev/null +++ b/home/tui/proton/proton-vpn.nix @@ -0,0 +1,7 @@ +{pkgs, ...}: { + # TODO: config + desktop file + home.packages = [ + pkgs.nur.repos.anotherhadi.proton-vpn-tui + pkgs.proton-vpn-cli + ]; +} diff --git a/home/programs/tui/shell/default.nix b/home/tui/shell/default.nix similarity index 100% rename from home/programs/tui/shell/default.nix rename to home/tui/shell/default.nix diff --git a/home/programs/tui/shell/direnv.nix b/home/tui/shell/direnv.nix similarity index 100% rename from home/programs/tui/shell/direnv.nix rename to home/tui/shell/direnv.nix diff --git a/home/programs/tui/shell/eza.nix b/home/tui/shell/eza.nix similarity index 100% rename from home/programs/tui/shell/eza.nix rename to home/tui/shell/eza.nix diff --git a/home/programs/tui/shell/fzf.nix b/home/tui/shell/fzf.nix similarity index 90% rename from home/programs/tui/shell/fzf.nix rename to home/tui/shell/fzf.nix index 281ac6e6..335deaf3 100644 --- a/home/programs/tui/shell/fzf.nix +++ b/home/tui/shell/fzf.nix @@ -24,6 +24,11 @@ in { "bg" = "-1"; "prompt" = muted; "pointer" = accent; + "border" = muted; + "preview-border" = muted; + "scrollbar" = muted; + "preview-scrollbar" = muted; + "gutter" = muted; }; defaultOptions = [ diff --git a/home/programs/tui/shell/starship.nix b/home/tui/shell/starship.nix similarity index 100% rename from home/programs/tui/shell/starship.nix rename to home/tui/shell/starship.nix diff --git a/home/programs/tui/shell/zoxide.nix b/home/tui/shell/zoxide.nix similarity index 100% rename from home/programs/tui/shell/zoxide.nix rename to home/tui/shell/zoxide.nix diff --git a/home/programs/tui/shell/zsh.nix b/home/tui/shell/zsh.nix similarity index 78% rename from home/programs/tui/shell/zsh.nix rename to home/tui/shell/zsh.nix index cc2a913a..c9540b65 100644 --- a/home/programs/tui/shell/zsh.nix +++ b/home/tui/shell/zsh.nix @@ -15,9 +15,6 @@ COLORTERM = "truecolor"; MANPAGER = "bat -l man -p"; }; - persistence."/persist" = lib.mkIf (config.var.impermanenceEnabled or false) { - files = [".zsh_history"]; - }; }; programs.zsh = { @@ -37,6 +34,7 @@ ]; history = { + path = lib.mkIf (config.var.impermanenceEnabled or false) "/persist${config.home.homeDirectory}/.zsh_history"; ignoreDups = true; findNoDups = true; expireDuplicatesFirst = true; @@ -63,7 +61,6 @@ cd = "z"; ls = "eza --icons=always --no-quotes"; tree = "eza --icons=always --tree --no-quotes"; - cat = "bat --theme=base16 --color=always --paging=never --tabs=2 --wrap=never --plain"; mkdir = "mkdir -p"; nix-shell = "nix-shell --command zsh"; grep = "rg --color=auto"; @@ -118,6 +115,33 @@ '') # bash '' + # cat: preview images inline (kitty graphics protocol, works in Ghostty) + # instead of dumping bat's binary garbage; falls back to bat otherwise. + cat() { + local -a imgs rest + local f + for f in "$@"; do + case "''${f:l}" in + *.png|*.jpg|*.jpeg|*.gif|*.bmp|*.webp|*.tiff|*.ico) + imgs+=("$f") + ;; + *) + rest+=("$f") + ;; + esac + done + + if (( ''${#imgs} )); then + for f in "''${imgs[@]}"; do + chafa --format=kitty "$f" + done + fi + + if (( ''${#rest} || ! ''${#imgs} )); then + bat --theme=base16 --color=always --paging=never --tabs=2 --wrap=never --plain "''${rest[@]}" + fi + } + # Suffix Aliases alias -s {nix,md,txt,yml,yaml,go}=nvim alias -s {json,jsonl}=jless @@ -145,6 +169,7 @@ bindkey '^[[1;5C' forward-word bindkey '^[[1;5D' backward-word bindkey '^F' _fzf_file_no_hidden + bindkey '^R' fzf-history-widget bindkey '^[[A' history-substring-search-up bindkey '^[[B' history-substring-search-down } diff --git a/home/programs/tui/myx/default.nix b/home/tui/spotify/default.nix similarity index 78% rename from home/programs/tui/myx/default.nix rename to home/tui/spotify/default.nix index 717e945d..96d2f55e 100644 --- a/home/programs/tui/myx/default.nix +++ b/home/tui/spotify/default.nix @@ -2,14 +2,12 @@ # theming, a live visualizer and synced lyrics. { config, + pkgs-unstable, pkgs, lib, ... -}: let - # https://github.com/NixOS/nixpkgs/pull/555072 - myx = pkgs.nur.repos.anotherhadi.myx; -in { - home.packages = [myx]; +}: { + home.packages = [pkgs-unstable.myx]; home.persistence."/persist" = lib.mkIf (config.var.impermanenceEnabled or false) { directories = [".config/myx"]; @@ -17,7 +15,7 @@ in { xdg.desktopEntries.myx = { name = "Spotify"; - exec = "${pkgs.ghostty}/bin/ghostty --window-padding-x=0 --window-padding-y=0 -e ${myx}/bin/myx"; + exec = "${pkgs.ghostty}/bin/ghostty --window-padding-x=0 --window-padding-y=0 -e ${pkgs-unstable.myx}/bin/myx"; icon = "spotify"; comment = "Control Spotify from the terminal"; categories = ["Audio" "Music"]; diff --git a/home/tui/tldr/default.nix b/home/tui/tldr/default.nix new file mode 100644 index 00000000..8e1b6c4c --- /dev/null +++ b/home/tui/tldr/default.nix @@ -0,0 +1,26 @@ +# TLDR provides simplified, example-based help pages for shell commands +{ + pkgs, + inputs, + ... +}: let + tealdeerCache = pkgs.runCommand "tealdeer-tldr-cache" {} '' + mkdir -p $out/tldr-pages + for d in ${inputs.tldr-pages-src}/pages ${inputs.tldr-pages-src}/pages.*; do + [ -d "$d" ] || continue + cp -r "$d" "$out/tldr-pages/$(basename "$d")" + done + if [ -d "$out/tldr-pages/pages" ] && [ ! -d "$out/tldr-pages/pages.en" ]; then + mv "$out/tldr-pages/pages" "$out/tldr-pages/pages.en" + fi + ''; +in { + programs = { + tealdeer = { + enable = true; # Fast tldr client + enableAutoUpdates = false; + settings.directories.cache_dir = "${tealdeerCache}"; + }; + zsh.shellAliases."tldr" = "tldr --quiet"; + }; +} diff --git a/hosts/laptop/configuration.nix b/hosts/laptop/configuration.nix index fe587986..dfc7b4d8 100644 --- a/hosts/laptop/configuration.nix +++ b/hosts/laptop/configuration.nix @@ -1,13 +1,17 @@ -{config, ...}: { +{ + config, + lib, + ... +}: { imports = [ - # Mostly system related configuration ../../nixos/nvidia.nix # CHANGEME: Remove this line if you don't have an Nvidia GPU ../../nixos/audio.nix ../../nixos/bluetooth.nix ../../nixos/fonts.nix ../../nixos/home-manager.nix ../../nixos/nix.nix - ../../nixos/systemd-boot.nix + ../../nixos/lanzaboot.nix # CHANGEME: Remove this line and uncomment the next one if you don't want to setup secure boot + # ../../nixos/systemd-boot.nix ../../nixos/tuigreet.nix ../../nixos/autologin.nix # Skip first TUIGreet login, use LUKS password to unlock the keyring ../../nixos/users.nix @@ -15,13 +19,10 @@ ../../nixos/hyprland.nix ../../nixos/steam.nix ../../nixos/kernel-hardening.nix - ../../home/programs/gui/helium/system.nix # I hate browser's configuration.. + ../../home/gui/helium/system.nix # I hate browser's configuration.. # CHANGEME: You should probably remove those things: ./wireguard.nix - ./persistence.nix # impermanence: what to keep once "/" is wiped on boot - ./usbguard.nix - ./disko.nix ./secrets # You should let those lines as is @@ -31,8 +32,65 @@ home-manager.users."${config.var.username}" = import ./home.nix; + # User password users.users.${config.var.username}.hashedPassword = "$y$j9T$A7gH534UczuBxulj9IfEu1$ImRy3lpYpemRWNVIkA7efKPWXneFiqhZnEF1aMkWcD8"; # CHANGEME: This is my password + # Impermanence: declares what should survive a wipe of "/". + environment.persistence."/persist" = { + hideMounts = true; + + directories = [ + "/etc/NetworkManager/system-connections" # Wifi connections, VPN + "/var/lib/bluetooth" # Bluetooth connections + "/var/lib/nixos" # keeps uid/gid stable across boots + "/var/lib/systemd/coredump" + "/var/lib/upower" # battery calibration state + "/var/lib/systemd/backlight" # remembers screen brightness + "/var/lib/systemd/timers" # last-run timestamps (e.g. nix gc weekly) + "/var/log" + "/var/db/sudo/lectured" # remembers that the sudo lecture was already shown + ]; + + files = [ + "/etc/machine-id" + "/etc/ssh/ssh_host_ed25519_key" + "/etc/ssh/ssh_host_ed25519_key.pub" + "/etc/ssh/ssh_host_rsa_key" + "/etc/ssh/ssh_host_rsa_key.pub" + "/var/lib/systemd/random-seed" # avoid a weak entropy pool on first boot + ]; + }; + + # USBGuard: + # The following line allow all USB devices until a proper policy is configured. + # Run `sudo usbguard generate-policy` with your devices plugged in, + # then set rules = "" and switch implicitPolicyTarget to "block". + # services.usbguard.implicitPolicyTarget = lib.mkForce "allow"; + services.usbguard = { + enable = true; + implicitPolicyTarget = "block"; + IPCAllowedUsers = [ + "root" + ]; + rules = '' + allow id 13fd:5900 name "External" + allow id 1d6b:0003 name "xHCI Host Controller" + allow id 1d6b:0002 name "xHCI Host Controller" + allow id 0bda:c85c name "Bluetooth Radio" + allow id 30c9:009f name "HP True Vision FHD Camera" + allow id 03f0:036b name "HP USB-C Dock G5" + allow id 03f0:066b name "HP USB-C Dock G5" + allow id 03f0:056b name "USB Audio" + allow id 0bda:8153 name "USB 10/100/1000 LAN" + allow id 046d:0ab7 name "Blue Microphones" + allow id 03f0:076b name "USB5734" + allow id 1532:02a1 name "Razer Ornata V3" + allow id 03f0:046b name "HP USB-C Dock G5" + allow id 03f0:086b name "USB2734" + allow id 1b1c:1b75 name "CORSAIR HARPOON RGB PRO Gaming Mouse" + ''; + }; + # Don't touch this system.stateVersion = "26.05"; } diff --git a/hosts/laptop/flake.nix b/hosts/laptop/flake.nix index 5f39688e..d210aae8 100644 --- a/hosts/laptop/flake.nix +++ b/hosts/laptop/flake.nix @@ -20,6 +20,7 @@ nixpkgs.lib.nixosSystem { inputs.helium-browser.nixosModules.default inputs.impermanence.nixosModules.impermanence inputs.disko.nixosModules.disko + inputs.lanzaboote.nixosModules.lanzaboote ./disko.nix ./configuration.nix ]; diff --git a/hosts/laptop/home.nix b/hosts/laptop/home.nix index ca472bbf..fc528c3d 100644 --- a/hosts/laptop/home.nix +++ b/hosts/laptop/home.nix @@ -3,49 +3,18 @@ inputs, lib, ... -}: { - imports = [ - # Programs - - ## GUI - ../../home/programs/gui/proton - ../../home/programs/gui/helium - ../../home/programs/gui/pkgs.nix - - ## TUI - inputs.nvf-config.homeManagerModules.default - ../../home/programs/tui/ghostty - ../../home/programs/tui/ilovetui - ../../home/programs/tui/shell - ../../home/programs/tui/git - ../../home/programs/tui/git/lazygit.nix - ../../home/programs/tui/git/signing.nix # CHANGEME: Change the key or remove this file - ../../home/programs/tui/nixy - ../../home/programs/tui/nix-utils - ../../home/programs/tui/myx - ../../home/programs/tui/elio - ../../home/programs/tui/wikiman - ../../home/programs/tui/navi - ../../home/programs/tui/pkgs.nix - - ## GROUPS - ../../home/programs/group/cybersecurity.nix - ../../home/programs/group/dev.nix - - # System (Desktop environment like stuff) - ../../home/system/hyprlock - ../../home/system/hyprland - ../../home/system/waybar - ../../home/system/swaync - ../../home/system/tofi - ../../home/system/mime - ../../home/system/udiskie - ../../home/system/termfilechooser - ../../home/system/clipboard - ../../home/system/hypridle - - ./variables.nix # Mostly user-specific configuration - ]; +}: let + utils = import ../../home/lib/utils.nix {inherit lib;}; +in { + imports = + utils.importAll ../../home/tui + ++ utils.importAll ../../home/gui + ++ utils.importAll ../../home/system # System (Desktop environment like stuff) + ++ [ + inputs.nvf-config.homeManagerModules.default # My vim config + ../../home/tui/git/signing.nix # CHANGEME: Change the key or remove this file + ./variables.nix # Mostly user-specific configuration + ]; home = { inherit (config.var) username; @@ -59,6 +28,7 @@ ".cache" ".steam" "Notes" + "Music" "Projects" "Documents" "Downloads" diff --git a/hosts/laptop/persistence.nix b/hosts/laptop/persistence.nix deleted file mode 100644 index 3a0b648f..00000000 --- a/hosts/laptop/persistence.nix +++ /dev/null @@ -1,29 +0,0 @@ -# Impermanence: declares what should survive a wipe of "/". -{ - environment.persistence."/persist" = { - hideMounts = true; - - directories = [ - "/etc/NetworkManager/system-connections" # Wifi connections, VPN - "/var/lib/bluetooth" # Bluetooth connections - "/var/lib/nixos" # keeps uid/gid stable across boots - "/var/lib/systemd/coredump" - "/var/lib/upower" # battery calibration state - "/var/lib/systemd/backlight" # remembers screen brightness - "/var/lib/systemd/timers" # last-run timestamps (e.g. nix gc weekly) - "/var/log" - "/var/cache/tuigreet" - "/var/cache/vulnix" - "/var/db/sudo/lectured" # remembers that the sudo lecture was already shown - ]; - - files = [ - "/etc/machine-id" - "/etc/ssh/ssh_host_ed25519_key" - "/etc/ssh/ssh_host_ed25519_key.pub" - "/etc/ssh/ssh_host_rsa_key" - "/etc/ssh/ssh_host_rsa_key.pub" - "/var/lib/systemd/random-seed" # avoid a weak entropy pool on first boot - ]; - }; -} diff --git a/hosts/laptop/secrets/secrets.yaml b/hosts/laptop/secrets/secrets.yaml index ad60ae75..e419d0b5 100644 --- a/hosts/laptop/secrets/secrets.yaml +++ b/hosts/laptop/secrets/secrets.yaml @@ -6,6 +6,8 @@ signing-pub-key: ENC[AES256_GCM,data:XuokZmCsnaNQ0rvVa3k81T4vtxw//r63xp1yHDLaNAM wireguard-private-key: ENC[AES256_GCM,data:5pEYyxiyKWMc9/3M37JimpeIrfZOtpwBnxL26q5d2griryqK8/CNsrv1Idw=,iv:2bZ/HlkwQ5Q6+BsiPWdjmdn3NbZ8Ck1RxP5dbGm3gDg=,tag:YeSEZlqj8QNLzItiSGjbPA==,type:str] anotherhadi-pgp-key: ENC[AES256_GCM,data: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,iv:rCIamsiBgMPfQkjclWGCsaHVjRNtf6md2bbLconbAvA=,tag:i7rcHD1mhOfa8KmRwvW+Yw==,type:str] myx-config: ENC[AES256_GCM,data:bugW3cUp/3L09C9FbBorWKjwkVh00tbysVhbVf4dcz3mGBeJfAsj8M5AAX3J9fs=,iv:EwgZYX0a1emHpUX4N2S4hDinnWfGnxZBnhS14JxQy0A=,tag:KR0Mm7lcxS9+abEKEGfhrw==,type:str] +chroncal-ics-urls: ENC[AES256_GCM,data:Cocu5SV50W7lYxb2AqK6lGFBaFv3qdymz2qJ/9IM/BGiKhvnWUfNDtlpKoLG1AOcXekup6YBxvo0iW1u+ipc69VbVKmu8aNImfmP4Ga4GdXVe1+7zA/KE3xAorOpg3HZfTLfy24mH6SMDey/yeYAOsQRrjmZfw+bn11LO98lKF4XOyz9LakjZHvxYHLJtd7YJsCjmmeOxlO0Hxu1yMD5K2yw7MkGBQP0G2oxaNAHXZz0XfsTVCG+MzQj1EaJMRBA/yCZVoYBIznwI6DUX3usr7YfzteIGa06kVIrmM7EOhDv8wgb22rUWAYNmWVDvF1z+eo0T5IXM4k3hnL4+mQ0gBzIgd32pRckWdZYeYbO7iXr/mWJulNLTHmFGYcyJXmp1DeafzlGfhZ4DG75TFPORlxoyKohsLmBzQZ1dMd5Gq5sFy0K4MfM1SCXodWnuvKQaDmi8QghRjEc9GdT8jLKjj8VTK6bI0PaYyoIvK4sNFHC8OWgGhiDs/5YxMx0Y+FYSddM/+IU3awhlcm/lgfNmltYzWSeWBbmFA2xKkw+tMPQh6ABOQd7uIhl/1+vOE63S8vBEbBcM8XPLzp24338+RBVjkcsapd+uG3OTU1OWn0eZTFDZwDKbn9lgS3eBRq3Dhqr2vKN5nIRRwMph5jsHe2RygHm6u57l5+q9KUhPTCer1OzNKf+dpSOGbC97N7KznSYJWOdCrEBnRs7OKC0Kvu5s+XyeUnzmSgBZwM8rNmv0Ke5FL96mcJXHvl5jdVx8JKJ7XA0NkAhGD5yF79uvNxY4a8637pJRPdJgykQgnZUyV0YgIVYyjwHOEV5+y9fJKC4WxnFyf/ySnfbb17XAzYUZDzlc4cz1m5DVdmOY/0PO2hCyjYj3my+GhlOiPOPPlyDYcc6aUJBTTtZj9S0oH/MhYD1eisZcYgsBhAfCPb5aN2qDRSgVGfye0qvIbVJlyx+/GNrW7sMSmmoPnQ86avoqr/EMEFJ10Z/ncWFaC4TW+T1JRZT94i2VXwYEjo=,iv:pM7HKNnOWay3biHBtNtD1iQfBm2nzq+kwJvevgDFPLE=,tag:3e+o9tNzG6QjmK/jhXjUaA==,type:str] +aerc-accounts: ENC[AES256_GCM,data:Ls76oe2izfAfaMeyazh+Liy9XnAFyXLRD2vNGCDBRmc8K3GfScpgytvHRGRVFbdS5lOXKyZGVL5g4kKU5DO0ORqA6ui4u2tIfK3vGLJKDffzrvWAxkN8sLJ6CLhkN+hlgWanng2aDiviX9dUrqIFfJycRLdastpHWeDgd5KX25bMDuBODlj+h4hSPE4kxYpOjcYEyRBRFPAWBfpqoRojflCvTdnyW1msKLl09iWdvHGBzQZmft+8UlDH3+UX7JUjE68vj/r9vObESwaNewo8A7UC9ctvJ1/klFPyphtcxjPiWCicZP+bhK/4bH/cE9zOtDsYjqJjf5U=,iv:by24yc7gu3iGCDSHxI/bZ1WTHB46UmLXcUw965koU4A=,tag:JRkKBmVr9q2Vv5IXL2oY+g==,type:str] sops: age: - enc: | @@ -17,7 +19,7 @@ sops: FSfQWnjhe/a7BJtJEcKZkjOQU0mYqlSu+uT2RA9diCQeRUJPRF+nAw== -----END AGE ENCRYPTED FILE----- recipient: age12yvtj49pfh3fqzqflscm0ek4yzrjhr6cqhn7x89gdxnlykq0xudq5c7334 - lastmodified: "2026-09-06T18:17:52Z" - mac: ENC[AES256_GCM,data:zT8rhA2aiNgouIkHxU+c14Fq+V2354yXkBYcoIqR0Sw4ERpTOzup38s0MC1zku3VfcWguXKsyWfiImvOHoDDa1Sqf+JOeYoQtLvV69b2+0cB+6kbHpXS62ML0L5YlWa8URW1MmEFI/XbUjsV3MWikyY5xnK2QzDWr/vhY6IK/io=,iv:YQnD0jTM9MmHNiQlWRawLoOcKCXXbXyXeu8ljnlk828=,tag:7pRWej2D1b5zghJ9TooFvA==,type:str] + lastmodified: "2026-09-24T16:50:58Z" + mac: ENC[AES256_GCM,data:icE86aggBij8y25K2D3UE4q4Jrzc8gwsTf/5DToR85yvXZfg06Uso7FeB4PuzaFwJ6OcRNZhFLrs3MsuVqBpOPtLjt/FyLG0hkgwQncu4lDF1BqWz2/TVEfvPthY0lIAvQq51RCSt7F/PJJBFxj4SS7eJokDQKD0cn0hmBh0MEE=,iv:E89QxFAnlOFPMrvnt2c2UfFwgOsWt/+EgVrVfzEiLe8=,tag:ijfoamRhL8MH+M2+5SWwGg==,type:str] unencrypted_suffix: _unencrypted version: 3.13.3 diff --git a/hosts/laptop/usbguard.nix b/hosts/laptop/usbguard.nix deleted file mode 100644 index 861f0ba4..00000000 --- a/hosts/laptop/usbguard.nix +++ /dev/null @@ -1,31 +0,0 @@ -# USBGuard: -# The following line allow all USB devices until a proper policy is configured. -# Run `sudo usbguard generate-policy` with your devices plugged in, -# then set rules = "" and switch implicitPolicyTarget to "block". -# services.usbguard.implicitPolicyTarget = lib.mkForce "allow"; -{ - services.usbguard = { - enable = true; - implicitPolicyTarget = "block"; - IPCAllowedUsers = [ - "root" - ]; - rules = '' - allow id 13fd:5900 name "External" - allow id 1d6b:0003 name "xHCI Host Controller" - allow id 1d6b:0002 name "xHCI Host Controller" - allow id 0bda:c85c name "Bluetooth Radio" - allow id 30c9:009f name "HP True Vision FHD Camera" - allow id 03f0:036b name "HP USB-C Dock G5" - allow id 03f0:066b name "HP USB-C Dock G5" - allow id 03f0:056b name "USB Audio" - allow id 0bda:8153 name "USB 10/100/1000 LAN" - allow id 046d:0ab7 name "Blue Microphones" - allow id 03f0:076b name "USB5734" - allow id 1532:02a1 name "Razer Ornata V3" - allow id 03f0:046b name "HP USB-C Dock G5" - allow id 03f0:086b name "USB2734" - allow id 1b1c:1b75 name "CORSAIR HARPOON RGB PRO Gaming Mouse" - ''; - }; -} diff --git a/hosts/server/home.nix b/hosts/server/home.nix index 37913d17..2117b926 100644 --- a/hosts/server/home.nix +++ b/hosts/server/home.nix @@ -14,7 +14,7 @@ ../../home/programs/tui/nixy ../../home/programs/tui/nix-utils ../../home/programs/tui/elio - ../../home/programs/tui/wikiman + ../../home/programs/tui/tealdeer ../../home/programs/tui/pkgs.nix ../../home/programs/group/dev.nix diff --git a/hosts/work/home.nix b/hosts/work/home.nix index d5de541a..ea03f124 100644 --- a/hosts/work/home.nix +++ b/hosts/work/home.nix @@ -23,7 +23,7 @@ ../../home/programs/tui/nix-utils ../../home/programs/tui/myx ../../home/programs/tui/elio - ../../home/programs/tui/wikiman + ../../home/programs/tui/tealdeer ../../home/programs/tui/navi ../../home/programs/tui/pkgs.nix diff --git a/nixos/lanzaboot.nix b/nixos/lanzaboot.nix new file mode 100644 index 00000000..182d15d9 --- /dev/null +++ b/nixos/lanzaboot.nix @@ -0,0 +1,55 @@ +# Secure Boot via lanzaboote (signed systemd-boot + unified kernel images) +# +# One-time setup on the machine (not handled by Nix): +# 1. sudo sbctl create-keys +# 2. Reboot into firmware setup, put Secure Boot in "Setup Mode" +# 3. nixos-rebuild switch (this signs the current generation with the new keys) +# 4. sudo sbctl enroll-keys --microsoft +# 5. Reboot, re-enable Secure Boot in firmware +{ + pkgs, + lib, + ... +}: { + boot = { + loader = { + efi.canTouchEfiVariables = true; + systemd-boot = { + enable = lib.mkForce false; + consoleMode = "auto"; + configurationLimit = 8; + }; + }; + + lanzaboote = { + enable = true; + pkiBundle = "/var/lib/sbctl"; + }; + + tmp.cleanOnBoot = true; + kernelPackages = pkgs.linuxPackages; # _latest, _zen, _hardened, _rt, _rt_latest, etc. + + # Silent boot + kernelParams = [ + "quiet" + "splash" + "rd.systemd.show_status=false" + "rd.udev.log_level=3" + "udev.log_priority=3" + "boot.shell_on_fail" + ]; + consoleLogLevel = 0; + initrd.verbose = false; + }; + + environment.systemPackages = [pkgs.sbctl]; + + # To avoid systemd services hanging on shutdown + systemd.settings.Manager = { + DefaultTimeoutStopSec = "10s"; + }; + + environment.persistence."/persist".directories = [ + "/var/lib/sbctl" + ]; +} diff --git a/nixos/tuigreet.nix b/nixos/tuigreet.nix index 1836e651..108f1cfc 100644 --- a/nixos/tuigreet.nix +++ b/nixos/tuigreet.nix @@ -48,8 +48,6 @@ in { # literally no documentation about this anywhere. # might be good to write about this... # https://www.reddit.com/r/NixOS/comments/u0cdpi/tuigreet_with_xmonad_how/ - # Unlock the gnome-keyring with the login password so apps (browser - # secrets via libsecret, ProtonVPN credentials, …) don't reprompt. systemd.services.greetd.serviceConfig = { Type = "idle"; StandardInput = "tty"; @@ -60,4 +58,8 @@ in { TTYVHangup = true; TTYVTDisallocate = true; }; + + environment.persistence."/persist".directories = [ + "/var/cache/tuigreet" + ]; } diff --git a/nixos/utils.nix b/nixos/utils.nix index 2ca1959e..d282c616 100644 --- a/nixos/utils.nix +++ b/nixos/utils.nix @@ -68,7 +68,12 @@ in { ]; }; gvfs.enable = true; - upower.enable = true; + upower = { + enable = true; + percentageLow = 10; + percentageCritical = 5; + percentageAction = 3; + }; power-profiles-daemon.enable = true; udisks2.enable = true; }; diff --git a/nixos/vulnix.nix b/nixos/vulnix.nix index 9c2fd28e..051f577b 100644 --- a/nixos/vulnix.nix +++ b/nixos/vulnix.nix @@ -24,4 +24,8 @@ RandomizedDelaySec = "1h"; }; }; + + environment.persistence."/persist".directories = [ + "/var/cache/vulnix" + ]; }