#+title: Droidnix: A Dendritic NixOS + Home Manager Configuration #+author: Henro Veijer #+options: toc:t num:nil htmlize:nil #+PROPERTY: header-args:nix :prologue "# --- This file has been auto-generated. For permanent changes alter the appropriate block in the README.org. ---" #+PROPERTY: header-args:sh :prologue "# --- This file has been auto-generated. For permanent changes alter the appropriate block in the README.org. ---" #+PROPERTY: header-args:bash :prologue "# --- This file has been auto-generated. For permanent changes alter the appropriate block in the README.org. ---" #+PROPERTY: header-args:css :prologue "/* --- This file has been auto-generated. For permanent changes alter the appropriate block in the README.org. --- */" #+PROPERTY: header-args:conf :prologue "# --- This file has been auto-generated. For permanent changes alter the appropriate block in the README.org. ---" #+PROPERTY: header-args:qml :prologue "// --- This file has been auto-generated. For permanent changes alter the appropriate block in the README.org. ---" #+PROPERTY: header-args:json :prologue "" #+PROPERTY: header-args:jsonc :prologue "// --- This file has been auto-generated. For permanent changes alter the appropriate block in the README.org. ---" #+PROPERTY: header-args:el :prologue ";; --- This file has been auto-generated. For permanent changes alter the appropriate block in the README.org. ---" #+PROPERTY: header-args:toml :prologue "# --- This file has been auto-generated. For permanent changes alter the appropriate block in the README.org. ---" #+language: en #+html_head: #+HTML_HEAD: #+HTML_HEAD: * Shortcuts [[#introduction][Introduction]] [[#the-assets-folder][The Assets Folder]] [[#the-actual-code][The Actual Code en configs]] --- * Introduction :intro: :PROPERTIES: :CUSTOM_ID: introduction :END: ** What is Droidnix Droidnix is a modular, declarative NixOS + Home Manager configuration system. with configurations managed via Emacs Org and Nix Flakes. The project is designed for reproducibility, maintainability, and cross-machine compatibility. *** Installed components: **** Core **** Hyprland *** Goals, project Structure, import hierarchy This project uses a **modular NixOS configuration** with **Hyprland** support, designed for **literate programming** and **cross-device reusability**. The Droidnix repository is organized into two main parts: 1. =.assets/=: Static, non-generated files (e.g., configs, scripts, themes). 2. Generated files and folders #+title: NixOS Configuration Structure * Root Level - = is the entry point and imports: - =generated/assets/= - =generated//modules/= - =generated/hosts/= * Generated Structure The =generated/= directory contains all generated configurations, divided into three main groups: =system=, =hyprland=, and =mangowc=. ** First Setup 1. Clone this repository. 2. Run the setup script: =./setup_droid=. 3. Tangle this Org file to generate Nix configurations: =C-c C-v t= in Emacs or use this: =emacs README.org --batch -f org-babel-tangle && emacs --batch --eval "(setq org-html-htmlize-output-type nil)" README.org -f org-html-export-to-html= 5. Build and switch: =sudo nixos-rebuild switch --flake .#=. --- * The Assets Folder :assets: :PROPERTIES: :CUSTOM_ID: the-assets-folder :END: The =.assets/= folder contains all static files, such as configs, scripts, and themes. These files are not generated and can be edited directly. ** =generated/assets/2_b_installed.conf= This is a list of additional apps to install #+BEGIN_SRC toml :tangle generated/assets/2_b_installed.conf :noweb yes :mkdirp yes :eval never #packages _1password-gui audacity baobab bat blender brave btop chromium cliphist comma direnv duf delta eza fd file fzf gimp git gparted grim grimblast gnome-calculator qalculate-gtk handbrake hyperfine just jq libreoffice lua nextcloud-client nextcloud-talk-desktop nix-index nix-output-monitor nh obsidian openssl pandoc postman python3 qdirstat ripgrep signal-desktop slurp solidtime-desktop spotify solaar swappy sweethome3d.application tea todoist tree usbutils vlc wev wget wl-clipboard wf-recorder yazi z-lua zed-editor zoxide #flatpaks eu.betterbird.Betterbird com.todoist.Todoist com.logseq.Logseq #+END_SRC ** =generated/assets/aliases.conf= This is a list of additional apps to install #+BEGIN_SRC conf :tangle generated/assets/aliases.conf :noweb yes :mkdirp yes :eval never #File & navigation repo=cd ~/Repos && ls -lah #Nix commands nps=xdg-open https://search.nixos.org #system commands please=sudo pls=sudo rb=sudo reboot po=sudo poweroff #flatpak commands fpl=flatpak list fps=flatpak search fpi=flatpak install fpr=flatpak run fpu=flatpak update #ssh commands nxc=ssh henrov@nextcloud.data-pro.nu #app shortcuts vs=code keys=hyprctl binds #+END_SRC * The Actual Code :code: :PROPERTIES: :CUSTOM_ID: the-actual-code :END: This section contains the Org blocks for tangling Nix code into the generated folders. ** =generated/flake.nix= The Nix flake definition for Droidnix. #+BEGIN_SRC nix :tangle flake.nix :noweb yes :mkdirp yes :eval never { description = "Droidnix: A dendritic NixOS + Home Manager configuration"; inputs = { nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable"; home-manager = { url = "github:nix-community/home-manager"; inputs.nixpkgs.follows = "nixpkgs"; }; quickshell = { url = "git+https://git.outfoxxed.me/outfoxxed/quickshell"; inputs.nixpkgs.follows = "nixpkgs"; }; import-tree.url = "github:vic/import-tree"; stylix = { url = "github:nix-community/stylix"; inputs.nixpkgs.follows = "nixpkgs"; }; flatpak = { url = "github:gmodena/nix-flatpak"; }; emacs-overlay = { url = "github:nix-community/emacs-overlay"; inputs.nixpkgs.follows = "nixpkgs"; }; zen-browser = { url = "github:youwen5/zen-browser-flake"; inputs.nixpkgs.follows = "nixpkgs"; }; hyprland.url = "github:hyprwm/Hyprland"; }; outputs = { self, nixpkgs, home-manager, import-tree, stylix, hyprland, emacs-overlay, zen-browser, flatpak ,... }: let system = "x86_64-linux"; flakeRoot = self; in { nixosConfigurations = { traveldroid = nixpkgs.lib.nixosSystem { inherit system; modules = [ ({ ... }: { nixpkgs.overlays = [ emacs-overlay.overlays.default ]; }) flatpak.nixosModules."nix-flatpak" ./generated/hosts/traveldroid/host.nix ./generated/users/henrov.nix ]; specialArgs = { inherit flakeRoot home-manager import-tree stylix hyprland zen-browser ; }; }; }; }; } #+END_SRC ** =generated/modules/traveldroid/system/colors.nix= Setting the colors for Droidnix. #+BEGIN_SRC nix :tangle generated/modules/traveldroid/system/colors.nix :noweb yes :mkdirp yes :eval never { lib, config, pkgs, flakeRoot, ... }: let colors = { crust = "#11111b"; mantle = "#181825"; base = "#1e1e2e"; surface0 = "#313244"; surface1 = "#45475a"; surface2 = "#585b70"; overlay0 = "#6c7086"; overlay1 = "#7f849c"; overlay2 = "#9399b2"; subtext0 = "#a6adc8"; subtext1 = "#bac2de"; text = "#cdd6f4"; rosewater = "#f5e0dc"; flamingo = "#f2cdcd"; pink = "#f5c2e7"; mauve = "#cba6f7"; red = "#f38ba8"; maroon = "#eba0ac"; peach = "#fab387"; yellow = "#f9e2af"; green = "#a6e3a1"; teal = "#94e2d5"; sapphire = "#74c7ec"; blue = "#89b4fa"; lavender = "#b4befe"; }; username = config.defaultUser or "henrov"; qmlContent = '' pragma Singleton // Catppuccin Mocha Palette - auto-generated, do not edit manually import QtQuick QtObject { readonly property color baseAlpha: Qt.rgba(30/255, 30/255, 46/255, 0.9) '' + lib.concatStringsSep "\n" ( lib.mapAttrsToList (name: value: " readonly property color ${name}: \"${value}\"" ) colors ) + "\n}"; in { home-manager.users.${username} = { home.file = { ".config/shared/colors.css" = { source = "${flakeRoot}/generated/.config/shared/colors.css"; force = true; }; ".config/quickshell/Colors.qml" = { text = qmlContent; force = true; }; ".config/quickshell/powermenu/Colors.qml" = { text = qmlContent; force = true; }; ".config/quickshell/powermenu/qmldir" = { text = "singleton Colors 1.0 Colors.qml"; force = true; }; }; }; } #+END_SRC ** =generated/hosts/traveldroid/boot.nix= #+BEGIN_SRC nix :tangle generated/hosts/traveldroid/boot.nix :noweb yes :mkdirp yes :eval never # --- This file has been auto-generated. For permanent changes alter the appropriate block in the README.org. --- { config, pkgs, lib, flakeRoot, ... }: { boot.loader = { systemd-boot.enable = true; efi.canTouchEfiVariables = true; efi.efiSysMountPoint = "/boot"; timeout = 5; }; boot.kernelPackages = pkgs.linuxPackages_latest; boot.kernelParams = [ "quiet" "splash" "udev.log_level=3" "rd.systemd.show_status=false" # Sleep / power management "mem_sleep_default=deep" # Use S3 deep sleep, fixes sleep not working "acpi_osi=Linux" # Tell ACPI this is a Linux system "acpi_backlight=native" # Proper backlight control # Intel GPU — fixes screen blinking on sleep/wake "i915.enable_psr=0" "i915.enable_psr2_sel_fetch=0" # Prevent nvme from waking the system "nvme.noacpi=1" ]; boot.consoleLogLevel = 0; #boot.initrd.systemd.enable = true; boot.initrd.availableKernelModules = [ "xhci_pci" "nvme" "usb_storage" "sd_mod" "rtsx_usb_sdmmc" ]; hardware.enableAllFirmware = true; boot.kernelModules = [ "kvm-intel" "asus_wmi" # Asus-specific power/fan/keyboard control ]; boot.plymouth = { enable = true; }; hardware.cpu.intel.updateMicrocode = lib.mkDefault config.hardware.enableRedistributableFirmware; nixpkgs.hostPlatform = lib.mkDefault "x86_64-linux"; # Power management powerManagement.enable = true; services.logind.settings.Login = { HandleSleepKey = "ignore"; HandleSleepKeyLongPress = "ignore"; }; services.thermald.enable = true; # Intel thermal management daemon services.tlp = { enable = true; settings = { CPU_SCALING_GOVERNOR_ON_AC = "performance"; CPU_SCALING_GOVERNOR_ON_BAT = "powersave"; CPU_ENERGY_PERF_POLICY_ON_BAT = "power"; PLATFORM_PROFILE_ON_AC = "performance"; PLATFORM_PROFILE_ON_BAT = "low-power"; }; }; } #+END_SRC ** =generated/hosts/traveldroid/hardware-configuration.nix= 1. Boot into NixOS Live ISO or your installed system. 2. Open a terminal. 3. Run: sudo nixos-generate-config --root /mnt (Omit --root /mnt if already running NixOS.) #+BEGIN_SRC nix :tangle generated/hosts/traveldroid/hardware-configuration.nix :noweb yes :mkdirp yes :eval never { hostname, pkgs, lib, modulesPath, user, config, ... }: { imports = [ # (modulesPath + "/installer/scan/not-detected.nix") #../../hardware/hardware.nix ]; boot.initrd.availableKernelModules = [ "xhci_pci" "nvme" "usb_storage" "sd_mod" "rtsx_usb_sdmmc" ]; boot.initrd.kernelModules = [ ]; boot.kernelModules = [ "kvm-intel" ]; boot.extraModulePackages = [ ]; fileSystems."/" = { device = "/dev/disk/by-uuid/69433a14-fbaf-401b-af85-cd1bbf02b4e2"; fsType = "ext4"; }; fileSystems."/boot" = { device = "/dev/disk/by-uuid/811D-0676"; fsType = "vfat"; options = [ "fmask=0077" "dmask=0077" ]; }; swapDevices = [ { device = "/dev/disk/by-uuid/b6c557c2-7682-460b-a5e7-8f6f2f429a3a"; } ]; nixpkgs.hostPlatform = lib.mkDefault "x86_64-linux"; hardware.cpu.intel.updateMicrocode = lib.mkDefault config.hardware.enableRedistributableFirmware; } #+END_SRC ** =generated/hosts/traveldroid/host.nix= #+BEGIN_SRC nix :tangle generated/hosts/traveldroid/host.nix :noweb yes :mkdirp yes :eval never { lib, config, pkgs, flakeRoot, import-tree, home-manager, ... }: let hostname = "traveldroid"; modulesPath = "${flakeRoot}/generated/modules/${hostname}"; hostModules = import-tree modulesPath; allModules = hostModules.imports; in { networking.hostName = hostname; system.stateVersion = "26.05"; ################################# # Locale ################################# i18n = { defaultLocale = "nl_NL.UTF-8"; extraLocales = [ "nl_NL.UTF-8/UTF-8" "en_US.UTF-8/UTF-8" ]; consoleKeyMap = "us"; }; time.timeZone = "Europe/Amsterdam"; ################################# # Imports ################################# imports = [ ../../../generated/users/henrov.nix ./boot.nix ./hardware-configuration.nix ] ++ allModules ++ [ home-manager.nixosModules.home-manager ]; ################################# # Home Manager integration ################################# home-manager.useGlobalPkgs = true; home-manager.useUserPackages = true; environment.systemPackages = [ pkgs.dconf ]; programs.dconf.enable = true; } #+END_SRC * generated/traveldroid/modules/apps ** =generated/modules/traveldroid/apps/2_b_installed.nix= This installs a list of apps #+BEGIN_SRC nix :tangle generated/modules/traveldroid/apps/2_b_installed.nix :noweb yes :mkdirp yes :eval never { lib, config, pkgs, flakeRoot, ... }: let ################################# # FILE ################################# confPath = "${flakeRoot}/generated/assets/2_b_installed.conf"; raw = builtins.readFile confPath; lines = lib.splitString "\n" raw; ################################# # CLEAN LINE ################################# cleanLine = line: let noCR = lib.replaceStrings [ "\r" ] [ "" ] line; noInlineComment = lib.head (lib.splitString "#" noCR); in lib.strings.trim noInlineComment; ################################# # PARSE SECTION ################################# parseSection = section: let result = builtins.foldl' (acc: line: let l = lib.strings.trim line; in if l == section then acc // { active = true; } else if lib.hasPrefix "#" l then acc // { active = false; } else if acc.active then acc // { entries = acc.entries ++ [ l ]; } else acc ) { active = false; entries = []; } lines; in builtins.filter (l: l != "") (map cleanLine result.entries); ################################# # NIX PACKAGES ################################# packageEntries = parseSection "#packages"; resolvePkg = name: let parts = lib.splitString "." name; found = lib.attrByPath parts null pkgs; in if found == null then throw '' packages.nix: package not found Token: ${name} File : ${confPath} '' else found; packages = map resolvePkg packageEntries; ################################# # FLATPAKS ################################# flatpakEntries = parseSection "#flatpaks"; in { ################################# # Allow unfree ################################# nixpkgs.config.allowUnfree = true; ################################# # System packages (Nix) ################################# environment.systemPackages = packages; ################################# # Flatpak setup ################################# services.flatpak.enable = true; services.flatpak.remotes = [ { name = "flathub"; location = "https://flathub.org/repo/flathub.flatpakrepo"; } ]; ################################# # Flatpak apps ################################# services.flatpak.packages = flatpakEntries; } #+END_SRC ** =generated/modules/traveldroid/apps/emacs/emacs.nix= This installs emacs #+BEGIN_SRC nix :tangle generated/modules/traveldroid/apps/emacs/emacs.nix :noweb yes :mkdirp yes :eval never { config, pkgs, lib, flakeRoot, ... }: let username = config.defaultUser or "henrov"; assetPath = "${flakeRoot}/generated/.config/emacs"; # Emacs package with Tree-sitter support emacsPkg = pkgs.emacs-pgtk.override { withTreeSitter = true; }; # Extra packages for Emacs via Home Manager emacsExtraPackages = epkgs: [ epkgs.manualPackages.treesit-grammars.with-all-grammars epkgs.nerd-icons epkgs.doom-modeline epkgs.diminish epkgs.eldoc epkgs.pulsar epkgs.which-key epkgs.expreg epkgs.vundo epkgs.puni epkgs.avy epkgs.consult epkgs.vertico epkgs.marginalia epkgs.crux epkgs.magit epkgs.nerd-icons-corfu epkgs.corfu epkgs.cape epkgs.orderless epkgs.yasnippet epkgs.yasnippet-snippets epkgs.rg epkgs.exec-path-from-shell epkgs.eat epkgs.rust-mode epkgs.rustic epkgs.nix-mode epkgs.hcl-mode epkgs.shell-pop epkgs.envrc epkgs.nixpkgs-fmt epkgs.f epkgs.gptel epkgs.catppuccin-theme epkgs.eldoc-box epkgs.sideline epkgs.sideline-flymake epkgs.sideline-eglot ]; in { # System-wide installation environment.systemPackages = [ emacsPkg ]; # Home Manager user-specific configuration for your default user home-manager.users = { ${username} = { home.sessionVariables = { EDITOR = "emacs"; XDG_SCREENSHOTS_DIR = "~/screenshots"; }; programs.emacs = { enable = true; package = emacsPkg; extraPackages = emacsExtraPackages; }; home.file = { ".emacs.d/early-init.el" = { source = "${assetPath}/early-init.el"; force = true; # <-- allow overwrite }; ".emacs.d/init.el" = { source = "${assetPath}/init.el"; force = true; # <-- allow overwrite }; }; }; }; } #+END_SRC ** =generated/modules/traveldroid/apps/flameshot.nix= This is top file of this level which contains just an import statement for all relevant files and/or the subfolder in this folder #+BEGIN_SRC nix :tangle generated/modules/traveldroid/apps/flameshot.nix :noweb yes :mkdirp yes :eval never { pkgs, config, lib, ... }: let username = config.defaultUser or "henrov"; in { ############################ # System-level packages ############################ environment.systemPackages = with pkgs; [ flameshot ]; ############################ # Home Manager user-level configuration ############################ home-manager.users."${username}" = { home.sessionVariables = { SCREENSHOT_TOOL = "flameshot"; USERNAME = username; }; # Create ~/Pictures/Screenshots by touching a dummy file home.file."Pictures/Screenshots/.keep" = { text = ""; # empty file }; services.flameshot = { enable = true; settings = { General = { uiColor = "#97cbbe"; contrastUiColor = "#1e1e2e"; showDesktopNotification = true; savePath = "/home/${username}/Pictures/Screenshots"; filenamePattern = "$Y-$m-$d_$H-$M-$S"; useGrimAdapter = true; }; }; }; }; } #+END_SRC ** =generated/modules/traveldroid/apps/kdeconnect.nix= This is top file of this level which contains just an import statement for all relevant files and/or the subfolder in this folder #+BEGIN_SRC nix :tangle generated/modules/traveldroid/apps/kdeconnect.nix :noweb yes :mkdirp yes :eval never # --- This file has been auto-generated. For permanent changes alter the appropriate block in the README.org. --- { config, pkgs, ... }: let username = config.defaultUser or "henrov"; in { environment.systemPackages = with pkgs; [ kdePackages.kdeconnect-kde ]; systemd.user.services.kdeconnect = { enable = true; description = "KDE Connect daemon"; wantedBy = ["default.target"]; serviceConfig = { ExecStart = "${pkgs.kdePackages.kdeconnect-kde}/bin/kdeconnectd"; Restart = "on-failure"; }; }; } #+END_SRC ** =generated/modules/traveldroid/apps/kitty.nix= This file sets up Kitty terminal #+BEGIN_SRC nix :tangle generated/modules/traveldroid/apps/kitty.nix :noweb yes :mkdirp yes :eval never { lib, pkgs, config, flakeRoot, ... }: let username = config.defaultUser or "henrov"; extraConfigFile = "${flakeRoot}/generated/.config/kitty/extra.conf"; extraConfig = if builtins.pathExists extraConfigFile then builtins.readFile extraConfigFile else ""; in { ################################# # System-wide install ################################# environment.systemPackages = [ pkgs.kitty ]; ################################# # Home Manager ################################# home-manager.users = { "${username}" = { programs.kitty = { enable = true; settings = { confirm_os_window_close = lib.mkForce 0; dynamic_background_opacity = lib.mkForce true; enable_audio_bell = lib.mkForce false; mouse_hide_wait = lib.mkForce "-1.0"; window_padding_width = lib.mkForce 10; background_opacity = lib.mkForce "0.5"; background_blur = lib.mkForce 5; }; extraConfig = '' ${extraConfig} # Theme include themes/Catppuccin-Mocha.conf ''; }; }; }; } #+END_SRC ** =generated/modules/traveldroid/apps/starship.nix= This file sets up starship prompt #+BEGIN_SRC nix :tangle generated/modules/traveldroid/apps/starship.nix :noweb yes :mkdirp yes :eval never { lib, config, pkgs, flakeRoot, ... }: let # Default username fallback username = config.defaultUser or "henrov"; # Path to the starship config in assets starshipConfSrc = "${flakeRoot}/generated/.config/starship.toml"; in { ################################# # Install Starship system-wide ################################# environment.systemPackages = [ pkgs.starship ]; ################################# # Home Manager user configuration ################################# home-manager.users = { ${username} = { home.file = { ".config/starship.toml" = { text = builtins.readFile "${starshipConfSrc}"; force = true; }; }; }; }; } #+END_SRC ** =generated/modules/traveldroid/apps/thunar.nix= This is top file of this level which contains just an import statement for all relevant files and/or the subfolder in this folder #+BEGIN_SRC nix :tangle generated/modules/traveldroid/apps/thunar.nix :noweb yes :mkdirp yes :eval never { pkgs, config, lib, ... }: let # Resolve the default username from host config username = config.defaultUser or "henrov"; in { ############################ # System-level packages ############################ environment.systemPackages = with pkgs; [ thunar # main file manager thunar-archive-plugin # zip, tar, rar, 7z support thunar-volman # auto-mount removable drives gvfs # support for external drives and network shares xarchiver # optional GUI archive manager tumbler # Showing thumbnails libmtp mtpfs jmtpfs ]; ############################ # Home Manager user-level configuration ############################ # Direct assignment to the user avoids recursiveUpdate issues home-manager.users."${username}" = { home.stateVersion = "26.05"; # required home.sessionVariables = { FILE_MANAGER = "thunar"; USERNAME = username; }; }; # Enable gvfs as a service services.gvfs.enable = true; } #+END_SRC ** =generated/modules/traveldroid/apps/wofi.nix= This is the install for Wofi, the launcher #+BEGIN_SRC nix :tangle generated/modules/traveldroid/apps/wofi.nix :noweb yes :mkdirp yes :eval never { lib, config, pkgs, flakeRoot, ... }: let username = config.defaultUser or "henrov"; assetPath = "${flakeRoot}/generated/.config/wofi"; in { environment.systemPackages = [ pkgs.wofi ]; home-manager.users = { ${username} = { home.file = { ".config/wofi/config" = { text = builtins.readFile "${assetPath}/config"; force = true; }; ".config/wofi/style.css" = { text = builtins.replaceStrings ["PLACEHOLDER_USERNAME"] [username] (builtins.readFile "${assetPath}/style.css"); force = true; }; }; }; }; } #+END_SRC ** =generated/modules/traveldroid/apps/zenbrowser.nix= This installs zen browser #+BEGIN_SRC nix :tangle generated/modules/traveldroid/apps/zenbrowser.nix :noweb yes :mkdirp yes :eval never { config, pkgs, lib, zen-browser, ... }: let # Grab the Zen Browser package for this host system zenBrowser = zen-browser.packages.${pkgs.stdenv.hostPlatform.system}.default; in { environment.systemPackages = [ zenBrowser ]; } #+END_SRC ** =generated/modules/traveldroid/apps/zsh.nix= This sets up the zsh in the terminal #+BEGIN_SRC nix :tangle generated/modules/traveldroid/apps/zsh.nix :noweb yes :mkdirp yes :eval never { lib, config, pkgs, flakeRoot, ... }: let ################################# # User config ################################# username = config.defaultUser or "henrov"; generatedZsh = "${flakeRoot}/generated/.config/zsh/.zshrc"; ################################# # Alias parsing ################################# aliasFile = "${flakeRoot}/generated/assets/aliases.conf"; content = builtins.readFile aliasFile; lines = lib.filter (l: l != "") (map (l: let noComment = builtins.head (lib.splitString "#" l); in lib.trim noComment ) (lib.splitString "\n" content)); parseLine = line: let parts = lib.splitString "=" line; in if lib.length parts < 2 then null else { name = lib.trim (lib.head parts); value = lib.trim (lib.concatStringsSep "=" (lib.tail parts)); }; parsed = lib.filter (x: x != null) (map parseLine lines); functions = lib.concatStringsSep "\n" (map (x: '' ${x.name}() { ${x.value} "$@" } '') parsed); in { ################################# # Packages ################################# environment.systemPackages = with pkgs; [ zsh oh-my-zsh starship zsh-syntax-highlighting ]; ################################# # Zsh config location ################################# environment.etc."zshenv".text = '' export ZDOTDIR=$HOME/.config/zsh ''; ################################# # Generated alias functions (system-wide) ################################# environment.etc."profile.d/99-alias-functions.sh".text = '' # system-wide functions generated from aliases.conf ${functions} ''; ################################# # Global zshrc ################################# environment.etc."zshrc".text = '' export ZSH=${pkgs.oh-my-zsh}/share/oh-my-zsh ZSH_THEME="" plugins=(git sudo extract colored-man-pages command-not-found history docker kubectl) source $ZSH/oh-my-zsh.sh # Init starship FIRST (prompt) eval "$(starship init zsh)" # Load alias functions if [ -f /etc/profile.d/99-alias-functions.sh ]; then source /etc/profile.d/99-alias-functions.sh fi # Load optional generated user config [ -f "${generatedZsh}" ] && source "${generatedZsh}" # Syntax highlighting MUST be last source ${pkgs.zsh-syntax-highlighting}/share/zsh-syntax-highlighting/zsh-syntax-highlighting.zsh ''; ################################# # Home Manager integration ################################# home-manager.users.${username} = { programs.zsh.enable = true; home.file.".config/zsh/.zshrc".source = generatedZsh; }; } #+END_SRC * generated/modules/traveldroid/desktop ** =generated/modules/traveldroid/desktop/fonts.nix= This file installs and configures fonts #+BEGIN_SRC nix :tangle generated/modules/traveldroid/desktop/fonts.nix :noweb yes :mkdirp yes :eval never { lib, pkgs, config, ... }: { fonts.packages = with pkgs; [ nerd-fonts.iosevka nerd-fonts.fira-code nerd-fonts.jetbrains-mono ]; } #+END_SRC ** =generated/modules/traveldroid/desktop/gtk.nix= Setting up GTK #+BEGIN_SRC nix :tangle generated/modules/traveldroid/desktop/gtk.nix :noweb yes :mkdirp yes :eval never { pkgs, config, lib, ... }: let username = config.defaultUser or "henrov"; in { environment.systemPackages = with pkgs; [ gtk3 gtk4 ]; home-manager.users."${username}" = { gtk = { enable = true; }; }; } #+END_SRC ** =generated/modules/traveldroid/desktop/hyprland.nix= Setting up Hyprland #+BEGIN_SRC nix :tangle generated/modules/traveldroid/desktop/hyprland.nix :noweb yes :mkdirp yes :eval never { lib, config, pkgs, flakeRoot, home-manager, inputs, ... }: let username = config.defaultUser or "henrov"; assetPath = "${flakeRoot}/generated/.config/hypr"; hyprlandPkg = pkgs.hyprland or pkgs.hyprland-git or inputs.hyprland.packages.${pkgs.system}.default; in { # Install Hyprland systemwide environment.systemPackages = [ hyprlandPkg ]; # Home Manager user configuration home-manager.users = { ${username} = { home.file = { ".config/hypr/animations.conf" = { source = "${assetPath}/animations.conf"; force = true; }; ".config/hypr/behaviour.conf" = { source = "${assetPath}/behaviour.conf"; force = true; }; ".config/hypr/bindings.conf" = { source = "${assetPath}/bindings.conf"; force = true; }; ".config/hypr/exec-once.conf" = { source = "${assetPath}/exec-once.conf"; force = true; }; ".config/hypr/hypridle.conf" = { source = "${assetPath}/hypridle.conf"; force = true; }; ".config/hypr/hyprland.conf" = { source = "${assetPath}/hyprland.conf"; force = true; }; ".config/hypr/hyprlock.conf" = { source = "${assetPath}/hyprlock.conf"; force = true; }; ".config/hypr/layer-rules.conf" = { source = "${assetPath}/layer-rules.conf"; force = true; }; ".config/hypr/layout.conf" = { source = "${assetPath}/layout.conf"; force = true; }; ".config/hypr/monitor-rules.conf" = { source = "${assetPath}/monitor-rules.conf"; force = true; }; ".config/hypr/theming.conf" = { source = "${assetPath}/theming.conf"; force = true; }; ".config/hypr/window-rules.conf" = { source = "${assetPath}/window-rules.conf"; force = true; }; ".config/hypr/workspace-rules.conf" = { source = "${assetPath}/workspace-rules.conf"; force = true; }; }; }; }; } #+END_SRC ** =generated/modules/traveldroid/desktop/stylix.nix= #+BEGIN_SRC nix :tangle generated/modules/traveldroid/desktop/stylix.nix :noweb yes :mkdirp yes :eval never { lib, config, pkgs, flakeRoot, stylix, ... }: let username = config.defaultUser or "henrov"; moduleName = "stylix"; assetPath = "${flakeRoot}/generated/.config/${moduleName}"; stylixConfFile = "${assetPath}/stylix.conf"; stylixConf = if builtins.pathExists stylixConfFile then builtins.readFile stylixConfFile else ""; cursorName = "phinger-cursors-light"; cursorSize = 24; in { ################################# # Enable Stylix module ################################# imports = [ stylix.nixosModules.stylix ]; ################################# # System packages ################################# environment.systemPackages = [ pkgs.feh pkgs.st ]; ################################# # Stylix system config ################################# stylix = { enable = true; base16Scheme = "${flakeRoot}/assets/traveldroid/theming/stylix/catppuccin-mocha.yaml"; polarity = "dark"; targets = { gtk.enable = true; qt.enable = true; }; cursor = { name = cursorName; package = pkgs.phinger-cursors; size = cursorSize; }; }; ################################# # Home Manager ################################# home-manager.users = { "${username}" = { ################################# # ONLY custom file (safe) ################################# home.file.".config/stylix/stylix.conf" = { text = stylixConf; force = true; }; ################################# # Environment variables ################################# home.sessionVariables = { STYLIX_CONF = "$HOME/.config/stylix/stylix.conf"; XCURSOR_THEME = cursorName; XCURSOR_SIZE = toString cursorSize; HYPRCURSOR_THEME = cursorName; HYPRCURSOR_SIZE = toString cursorSize; }; }; }; } #+END_SRC ** =generated/modules/traveldroid/desktop/wallpaper.nix= Setting up wallpaper engine + wallpaper gui #+BEGIN_SRC nix :tangle generated/modules/traveldroid/desktop/wallpaper.nix :noweb yes :mkdirp yes :eval never { lib, config, pkgs, flakeRoot, ... }: let username = config.defaultUser or "henrov"; homeDir = "/home/${username}"; wallpaperSrc = "${flakeRoot}/assets/traveldroid/Wallpapers"; wallpaperDst = "${homeDir}/Wallpapers"; randoScript = "${homeDir}/Wallpapers/scripts/randomizeWallpapers.sh"; in { # Make bash available environment.systemPackages = [ pkgs.bash pkgs.rsync pkgs.jq pkgs.awww pkgs.waypaper pkgs.socat ]; # Create the copy script using Home Manager, following Waybar style home-manager.users = { ${username} = { home.file = { "copy-wallpapers.sh" = { text = '' #!/run/current-system/sw/bin/bash set -euo pipefail echo "Running as $(whoami)" echo "Copying wallpapers from ${wallpaperSrc} to ${wallpaperDst} ..." if [ ! -d "${wallpaperSrc}" ]; then echo "ERROR: ${wallpaperSrc} does not exist" exit 1 fi mkdir -p "${wallpaperDst}" # Simple copy, overwrite everything cp -r "${wallpaperSrc}/." "${wallpaperDst}/" # Fix permissions chmod -R u+rwx "${wallpaperDst}" echo "Done copying wallpapers." ''; executable = true; force = true; }; }; }; }; # User service to run the script that copies the Wallpaperstuff systemd.user.services.copyWallpapers = { description = "Copy wallpapers from repo to ~/Wallpapers"; serviceConfig = { Type = "oneshot"; ExecStart = "${homeDir}/copy-wallpapers.sh"; Restart = "no"; WorkingDirectory = homeDir; }; wantedBy = [ "default.target" ]; }; # User service to randomize wallpapers systemd.user.services.randomizeWallpapers = { description = "Randomize wallpapers in ~/Wallpapers/pictures"; serviceConfig = { Type = "oneshot"; ExecStart = "${randoScript}"; Restart = "no"; WorkingDirectory = homeDir; }; wantedBy = [ "default.target" ]; }; ############################ # Random background per workspace at logon ############################ systemd.user.services.workspaceWallpapers = { description = "Dynamic wallpapers per workspace for Hyprland"; after = [ "graphical-session.target" ]; wants = [ "graphical-session.target" ]; serviceConfig = { Type = "simple"; ExecStart = "${homeDir}/Wallpapers/scripts/workspace-wallpapers.sh"; Restart = "on-failure"; RestartSec = 5; WorkingDirectory = homeDir; Environment = [ "HYPRLAND_INSTANCE_SIGNATURE=${builtins.getEnv "HYPRLAND_INSTANCE_SIGNATURE"}" "WAYLAND_DISPLAY=wayland-1" "PATH=/run/current-system/sw/bin:/usr/bin:/bin" ]; }; wantedBy = [ "default.target" ]; }; } #+END_SRC ** =generated/modules/traveldroid/desktop/waybar.nix= This file installs and configures waybar #+BEGIN_SRC nix :tangle generated/modules/traveldroid/desktop/waybar.nix :noweb yes :mkdirp yes :eval never { lib, config, pkgs, flakeRoot, ... }: let # Use the config option defaultUser directly, fallback to "henrov" username = config.defaultUser or "henrov"; basePath = "${flakeRoot}/generated/.config"; assetPath = "${flakeRoot}/generated/.config/waybar"; in { # Install Waybar system-wide environment.systemPackages = [ pkgs.waybar ]; home-manager.users = { ${username} = { home.file = { ".config/waybar/config.jsonc" = { text = builtins.readFile "${assetPath}/config.jsonc"; force = true; }; ".config/waybar/style-dark.css" = { text = builtins.replaceStrings ["henrov"] [username] (builtins.readFile "${assetPath}/style-dark.css"); force = true; }; ".config/scripts/bluetooth-status.sh" = { text = builtins.readFile "${basePath}/scripts/bluetooth-status.sh"; force = true; executable = true; }; ".config/scripts/hypr-workspaces.sh" = { text = builtins.readFile "${basePath}/scripts/hypr-workspaces.sh"; force = true; executable = true; }; ".config/scripts/hypr-workspacesmenu.sh" = { text = builtins.readFile "${basePath}/scripts/hypr-workspacesmenu.sh"; force = true; executable = true; }; }; }; }; # Systemd user service for Waybar systemd.user.services.waybar = { description = "Waybar for Hyprland"; after = [ "graphical-session.target" ]; serviceConfig = { ExecStart = "${pkgs.waybar}/bin/waybar"; Restart = "always"; Environment = '' WAYLAND_DISPLAY=${config.environment.sessionVariables.WAYLAND_DISPLAY or "wayland-0"} XDG_CURRENT_DESKTOP=Hyprland ''; }; wantedBy = [ "default.target" ]; }; } #+END_SRC ** =generated/modules/traveldroid/desktop/wayland.nix= #+BEGIN_SRC nix :tangle generated/modules/traveldroid/desktop/wayland.nix :noweb yes :mkdirp yes :eval never { lib, config, pkgs, ... }: { ################################# # Core Wayland packages ################################# environment.systemPackages = with pkgs; [ wayland wl-clipboard # optional but commonly used for copy/paste ]; ################################# # enable graphics stack ################################# hardware.graphics.enable = true; ################################# # Optional session variables for Wayland ################################# environment.sessionVariables = { # Forces some apps to use Wayland NIXOS_OZONE_WL = "1"; }; } #+END_SRC ** =generated/modules/traveldroid/desktop/xdg.nix= This sets the XDG implementation #+BEGIN_SRC nix :tangle generated/modules/traveldroid/desktop/xdg.nix :noweb yes :mkdirp yes :eval never { lib, config, pkgs, flakeRoot, ... }: let username = config.defaultUser or "henrov"; homeDir = "/home/${username}"; # Portal backends basePortal = pkgs.xdg-desktop-portal-gtk; hyprlandPortal = pkgs.xdg-desktop-portal-hyprland; in { ################################# # XDG Desktop Portals (system) ################################# xdg.portal.enable = true; xdg.portal.extraPortals = [ basePortal hyprlandPortal ]; xdg.portal.config = { "org.freedesktop.impl.portal.Screencast".backend = "hyprland"; }; ################################# # System packages ################################# environment.systemPackages = [ basePortal hyprlandPortal ]; ################################# # Home Manager user config ################################# home-manager.users.${username} = { ################################# # User packages ################################# home.packages = [ basePortal hyprlandPortal ]; ################################# # XDG user directories (HOME ONLY) ################################# xdg.userDirs = { enable = true; createDirectories = true; desktop = null; download = "${homeDir}/Downloads"; documents = "${homeDir}/Documents"; pictures = "${homeDir}/Pictures"; music = null; publicShare = null; templates = "${homeDir}/Experiments"; videos = "${homeDir}/Videos"; extraConfig = { XDG_PROJECTS_DIR = "${homeDir}/Projects"; XDG_WORK_DIR = "${homeDir}/Work"; }; }; }; } #+END_SRC * generated/modules/traveldroid/system ** =generated/modules/traveldroid/system/audio.nix= #+BEGIN_SRC nix :tangle generated/modules/traveldroid/system/audio.nix :noweb yes :mkdirp yes :eval never { lib, config, pkgs, ... }: { ############################ # Audio system ############################ environment.systemPackages = with pkgs; [ pulseaudio # PulseAudio daemon pavucontrol # GUI mixer pamixer # CLI mixer playerctl # Player controls ]; } #+END_SRC ** =generated/modules/traveldroid/system/avahi.nix= Avahi helps discovering services #+BEGIN_SRC nix :tangle generated/modules/traveldroid/system/avahi.nix :noweb yes :mkdirp yes :eval never { ... }: { services.avahi = { enable = true; nssmdns4 = true; publish = { enable = true; addresses = true; }; }; } #+END_SRC ** =generated/modules/traveldroid/system/bluetooth.nix= Installing Bluetooth services and supporting aps #+BEGIN_SRC nix :tangle generated/modules/traveldroid/system/bluetooth.nix :noweb yes :mkdirp yes :eval never { lib, config, pkgs, home-manager, ... }: let username = config.defaultUser or "henrov"; in { ############################ # Bluetooth daemon ############################ hardware.bluetooth = { enable = true; powerOnBoot = true; package = pkgs.bluez; }; environment.systemPackages = with pkgs; [ blueman ]; } #+END_SRC ** =generated/modules/traveldroid/system/copy_scripts.nix= This copies any scripts from /generated/.config/scripts to ~/.config/scripts and makes any .sh files executable. #+BEGIN_SRC nix :tangle generated/modules/traveldroid/system/copy_scripts.nix :noweb yes :mkdirp yes :eval never { lib, config, pkgs, flakeRoot, ... }: let username = config.defaultUser or "henrov"; configPath = flakeRoot + "/generated/.config/scripts"; allFiles = lib.filesystem.listFilesRecursive configPath; toRelative = file: let base = toString flakeRoot + "/generated/"; relative = lib.removePrefix base (toString file); in builtins.unsafeDiscardStringContext relative; isShellScript = file: lib.hasSuffix ".sh" (toString file); toFileEntry = file: { name = toRelative file; value = { source = file; executable = isShellScript file; force = true; }; }; in { home-manager.users = { ${username} = { home.file = builtins.listToAttrs (map toFileEntry allFiles); }; }; } #+END_SRC ** =generated/modules/traveldroid/system/dbus.nix= This sets the dbus implementation #+BEGIN_SRC nix :tangle generated/modules/traveldroid/system/dbus.nix :noweb yes :mkdirp yes :eval never { config, pkgs, ... }: { # Enable classic D-Bus service services.dbus.enable = true; # Use default dbus package (classic D-Bus) services.dbus.dbusPackage = pkgs.dbus; # Include some essential system packages so shell and tools exist environment.systemPackages = with pkgs; [ bashInteractive coreutils ]; # Do not attempt to wrap dbus-daemon-launch-helper manually # No extra security.wrappers needed } #+END_SRC ** =generated/modules/traveldroid/system/firewall.nix= This sets the firewall. #+BEGIN_SRC nix :tangle generated/modules/traveldroid/system/firewall.nix :noweb yes :mkdirp yes :eval never { pkgs, ... }: { # Use nftables as the firewall backend networking.nftables.enable = true; networking.firewall = { enable = true; filterForward = false; # don't filter forwarded traffic # outbound is allowed by default UNLESS you've set: # LAN-only ports — Wi-Fi interface interfaces."wlan0" = { allowedTCPPorts = [ 22 # SSH 80 # allow HTTP globally for outbound 443 # allow HTTPS globally for outbound 631 # CUPS / IPP network printing 9100 # AppSocket/JetDirect printing 6566 # SANE network scanner 57621 # Spotify Connect 57622 # Spotify local file sync ]; allowedTCPPortRanges = [ { from = 1714; to = 1764; } # KDE Connect ]; allowedUDPPorts = [ 5353 # mDNS / Avahi (printer + device discovery) 631 # CUPS / IPP 67 # DHCP 123 # NTP time sync 1900 # UPnP device discovery 57621 # Spotify Connect ]; allowedUDPPortRanges = [ { from = 1714; to = 1764; } # KDE Connect ]; }; # LAN-only ports — ethernet (ready for when you plug in) interfaces."enp0s31f6" = { allowedTCPPorts = [ 631 # CUPS / IPP network printing 9100 # AppSocket/JetDirect printing 6566 # SANE network scanner 57621 # Spotify Connect 57622 # Spotify local file sync ]; allowedTCPPortRanges = [ { from = 1714; to = 1764; } # KDE Connect ]; allowedUDPPorts = [ 5353 # mDNS / Avahi (printer + device discovery) 631 # CUPS / IPP 67 # DHCP 123 # NTP time sync 1900 # UPnP device discovery 57621 # Spotify Connect ]; allowedUDPPortRanges = [ { from = 1714; to = 1764; } # KDE Connect ]; }; }; # CLI tool for temporary rule changes without rebuilding # Usage: sudo nixos-firewall-tool open tcp 8080 environment.systemPackages = with pkgs; [ nixos-firewall-tool ]; } #+END_SRC ** =generated/modules/traveldroid/system/hypridle.nix= This installs hypridle #+BEGIN_SRC nix :tangle generated/modules/traveldroid/system/hypridle.nix :noweb yes :mkdirp yes :eval never { lib, config, pkgs, flakeRoot, ... }: let username = config.defaultUser or "henrov"; basePath = "${flakeRoot}/generated/.config"; assetPath = "${flakeRoot}/generated/.config/hypr"; in { ################################# # Install hypridle system-wide ################################# environment.systemPackages = [ pkgs.hypridle ]; ################################# # Deploy config ################################# home-manager.users = { ${username} = { home.file = { ".config/hypr/hypridle.conf" = { text = builtins.readFile "${assetPath}/hypridle.conf"; force = true; }; }; }; }; ################################# # Systemd user service ################################# systemd.user.services.hypridle = { description = "Hypridle (Hyprland idle daemon)"; after = [ "hyprland-session.target" ]; bindsTo = [ "hyprland-session.target" ]; serviceConfig = { ExecStart = "${pkgs.hypridle}/bin/hypridle"; Restart = "on-failure"; RestartSec = "5s"; Environment = [ "HOME=/home/${username}" "WAYLAND_DISPLAY=wayland-1" "XDG_RUNTIME_DIR=/run/user/1000" ]; }; wantedBy = [ "hyprland-session.target" ]; }; } #+END_SRC ** =generated/modules/traveldroid/system/hyprlock.nix= This installs hyprlock #+BEGIN_SRC nix :tangle generated/modules/traveldroid/system/hyprlock.nix :noweb yes :mkdirp yes :eval never { lib, config, pkgs, flakeRoot, ... }: let username = config.defaultUser or "henrov"; basePath = "${flakeRoot}/generated/.config"; assetPath = "${flakeRoot}/generated/.config/hypr"; in { ################################# # Install hyprlock system-wide ################################# environment.systemPackages = [ pkgs.hyprlock ]; ################################# # Deploy configuration file ################################# home-manager.users = { ${username} = { home.file = { ".config/hypr/hyprlock.conf" = { text = builtins.readFile "${assetPath}/hyprlock.conf"; force = true; }; }; }; }; ################################# # Optional: helper systemd user service (manual start use) ################################# systemd.user.services.hyprlock = { description = "Hyprlock (manual lock session)"; after = [ "graphical-session.target" ]; serviceConfig = { ExecStart = "${pkgs.hyprlock}/bin/hyprlock"; Restart = "no"; Environment = '' WAYLAND_DISPLAY=${config.environment.sessionVariables.WAYLAND_DISPLAY or "wayland-0"} XDG_CURRENT_DESKTOP=Hyprland ''; }; wantedBy = [ ]; }; } #+END_SRC ** =generated/modules/traveldroid/system/gnome-keyring.nix= This sets the dbus implementation #+BEGIN_SRC nix :tangle generated/modules/traveldroid/system/gnome-keyring.nix :noweb yes :mkdirp yes :eval never { config, pkgs, ... }: { ################################################## # Core services ################################################## # Enable GNOME Keyring services.gnome.gnome-keyring.enable = true; ################################################## # PAM (auto unlock keyring on login) ################################################## security.pam.services = { login.enableGnomeKeyring = true; greetd.enableGnomeKeyring = true; sddm.enableGnomeKeyring = true; gdm.enableGnomeKeyring = true; }; ################################################## # Environment packages ################################################## environment.systemPackages = with pkgs; [ polkit_gnome seahorse libsecret ]; ################################################## # Security / Polkit ################################################## security.polkit.enable = true; } #+END_SRC ** =generated/modules/traveldroid/system/login-tuigreet.nix= This sets up tuigreeter which is not fancy but imo fits the aesthetic I am aiming for #+BEGIN_SRC nix :tangle generated/modules/traveldroid/system/login-tuigreet.nix :noweb yes :mkdirp yes :eval never { config, pkgs, lib, ... }: let tuigreetBin = "${pkgs.tuigreet}/bin/tuigreet"; sessionsDir = "${pkgs.hyprland}/share/wayland-sessions"; in { ################################# # Greetd (tuigreet) ################################# services.greetd = { enable = true; settings = { default_session = { command = '' ${tuigreetBin} \ --time \ --remember \ --remember-session \ --sessions ${sessionsDir} \ --cmd "start-hyprland" ''; user = "greeter"; }; }; }; ################################# # Fix TTY / boot noise issues ################################# systemd.services.greetd.serviceConfig = { Type = "idle"; StandardInput = "tty"; StandardOutput = "tty"; StandardError = "journal"; # Prevent boot log spam on tty TTYReset = true; TTYVHangup = true; TTYVTDisallocate = true; }; } #+END_SRC ** =generated/modules/traveldroid/system/networking.nix= This sets the networking. #+BEGIN_SRC nix :tangle generated/modules/traveldroid/system/networking.nix :noweb yes :mkdirp yes :eval never { lib, config, pkgs, ... }: { ################################# # Networking core ################################# networking = { # Let DHCP be default unless overridden elsewhere useDHCP = lib.mkDefault true; ################################# # NetworkManager (primary stack) ################################# networkmanager = { enable = true; # Use iwd backend for WiFi wifi.backend = "iwd"; }; ################################# # iwd (WiFi daemon) ################################# wireless.iwd = { enable = true; # Allow user control via NM / CLI settings.General.EnableNetworkConfiguration = true; }; }; ################################# # System packages ################################# environment.systemPackages = [ pkgs.networkmanager pkgs.linux-firmware pkgs.networkmanagerapplet pkgs.networkmanager_dmenu pkgs.iwgtk ]; } #+END_SRC ** =generated/modules/traveldroid/system/nix.nix= #+BEGIN_SRC nix :tangle generated/modules/traveldroid/system/nix.nix :noweb yes :mkdirp yes :eval never { lib, config, ... }: { nix.settings = { experimental-features = [ "nix-command" "flakes" ]; download-buffer-size = 536870912; # 512 MB cores = 2; max-jobs = 1; }; } #+END_SRC ** =generated/modules/traveldroid/system/printing.nix= This sets the dbus implementation #+BEGIN_SRC nix :tangle generated/modules/traveldroid/system/printing.nix :noweb yes :mkdirp yes :eval never { lib, config, pkgs, ... }: { ############################ # Printing system ############################ services.printing.enable = true; # enable CUPS printing service ############################ # System packages for GUI management ############################ environment.systemPackages = with pkgs; [ system-config-printer # GUI to manage printers ]; } #+END_SRC ** =generated/modules/traveldroid/system/quickshell.nix= This sets the dbus implementation #+BEGIN_SRC nix :tangle generated/modules/traveldroid/system/quickshell.nix :noweb yes :mkdirp yes :eval never { pkgs, lib, config, flakeRoot, ... }: let username = config.defaultUser or "henrov"; quickshellPath = flakeRoot + "/generated/.config/quickshell"; allFiles = lib.filesystem.listFilesRecursive quickshellPath; toRelative = file: let base = toString flakeRoot + "/generated/"; relative = lib.removePrefix base (toString file); in builtins.unsafeDiscardStringContext relative; toFileEntry = file: { name = toRelative file; value = { source = file; force = true; }; }; in { environment.systemPackages = with pkgs; [ quickshell qt6.qtdeclarative qt6.qttools qt6.qtsvg qt6.qtimageformats qt6.qtmultimedia qt6.qt5compat ]; qt = { enable = true; platformTheme = "qt5ct"; }; home-manager.users = { ${username} = { home.file = builtins.listToAttrs (map toFileEntry allFiles); }; }; } #+END_SRC ** =generated/modules/traveldroid/system/swaync.nix= This sets the dbus implementation #+BEGIN_SRC nix :tangle generated/modules/traveldroid/system/swaync.nix :noweb yes :mkdirp yes :eval never { lib, config, pkgs, flakeRoot, ... }: let username = config.defaultUser or "henrov"; assetPath = "${flakeRoot}/generated/.config/swaync"; in { environment.systemPackages = [ pkgs.swaynotificationcenter pkgs.libnotify ]; home-manager.users.${username} = { # Do NOT enable services.swaync — it would claim the config files # and conflict with our home.file entries below. home.file = { ".config/swaync/config.json" = { text = builtins.readFile "${assetPath}/config.json"; force = true; }; ".config/swaync/style.css" = { text = builtins.replaceStrings ["henrov"] [username] (builtins.readFile "${assetPath}/style.css"); force = true; }; }; }; # Autostart swaync as a systemd user service instead systemd.user.services.swaync = { description = "SwayNotificationCenter"; after = [ "graphical-session.target" ]; serviceConfig = { ExecStart = "${pkgs.swaynotificationcenter}/bin/swaync"; Restart = "always"; Environment = [ "WAYLAND_DISPLAY=${config.environment.sessionVariables.WAYLAND_DISPLAY or "wayland-1"}" "XDG_CURRENT_DESKTOP=Hyprland" ]; }; wantedBy = [ "default.target" ]; }; } #+END_SRC * generated/users ** =generated/users/= This is the default user, just search and replace henrov another name if you want to change #+BEGIN_SRC nix :tangle generated/users/henrov.nix :noweb yes :mkdirp yes :eval never { lib, config, pkgs, ... }: let username = "henrov"; in { ################################# # NixOS system user ################################# users.users.${username} = { isNormalUser = true; home = "/home/${username}"; hashedPassword = "$6$S7iShgBxB.77CwmP$i0njK.2r3OL5UEvgZbmwZ0rnpZ4QyJcv8p9uCmJ4AiVPSMXkQkIwMLzyAOnJ0q8.tPLIp/7EquEIZeK8qbmgw/"; extraGroups = [ "wheel" "networkmanager" "bluetooth" "input" ]; ignoreShellProgramCheck = true; # <-- avoids the assertion shell = pkgs.zsh; }; ################################# # Home Manager user definition ################################# home-manager.users = { ${username} = { home.username = username; home.homeDirectory = "/home/${username}"; home.stateVersion = "26.05"; programs.zsh.enable = true; home.packages = [ # add packages here ]; # Activation to ensure the directory is writable home.activation.fixStylixPermissions = '' mkdir -p $HOME/.config chmod -R u+rwx $HOME/.config ''; # Locale and timezone settings home.sessionVariables = { LANG = "nl_NL.UTF-8"; LC_ALL = "nl_NL.UTF-8"; TZ = "Europe/Amsterdam"; }; }; }; } #+END_SRC * These are all the prepared config files :PROPERTIES: :CUSTOM_ID: the-config-files :END: ** =generated/.config/emacs/early-init.el= This contaions emacs #+BEGIN_SRC el :tangle generated/.config/emacs/early-init.el :noweb yes :mkdirp yes :eval never ;;; package --- early init -*- lexical-binding: t -*- ;;; Commentary: ;;; Prevents white flash and better Emacs defaults ;;; Code: (set-language-environment "UTF-8") (setq-default default-frame-alist '((background-color . "#1e1e2e") (bottom-divider-width . 1) ; Thin horizontal window divider (foreground-color . "#bac2de") ; Default foreground color (fullscreen . maximized) ; Maximize the window by default (horizontal-scroll-bars . nil) ; No horizontal scroll-bars (left-fringe . 8) ; Thin left fringe (menu-bar-lines . 0) ; No menu bar (right-divider-width . 1) ; Thin vertical window divider (right-fringe . 8) ; Thin right fringe (tool-bar-lines . 0) ; No tool bar (undecorated . t) ; Remove extraneous X decorations (vertical-scroll-bars . nil)) ; No vertical scroll-bars user-full-name "Henrov henrov" ; ME! ;; memory configuration ;; Higher garbage collection threshold, prevents frequent gc locks, reset later gc-cons-threshold most-positive-fixnum ;; Ignore warnings for (obsolete) elisp compilations byte-compile-warnings '(not obsolete) ;; And other log types completely warning-suppress-log-types '((comp) (bytecomp)) ;; Large files are okay in the new millenium. large-file-warning-threshold 100000000 ;; dont show garbage collection messages at startup, will reset later garbage-collection-messages nil ;; native compilation package-native-compile t native-comp-warning-on-missing-source nil native-comp-async-report-warnings-errors 'silent ;; Read more based on system pipe capacity read-process-output-max (max (* 10240 10240) read-process-output-max) ;; scroll configuration scroll-margin 0 ; Lets scroll to the end of the margin scroll-conservatively 100000 ; Never recenter the window scroll-preserve-screen-position 1 ; Scrolling back and forth ;; frame config ;; Improve emacs startup time by not resizing to adjust for custom settings frame-inhibit-implied-resize t ;; Dont resize based on character height / width but to exact pixels frame-resize-pixelwise t ;; backups & files backup-directory-alist '(("." . "~/.backups/")) ; Don't clutter backup-by-copying t ; Don't clobber symlinks create-lockfiles nil ; Don't have temp files delete-old-versions t ; Cleanup automatically kept-new-versions 6 ; Update every few times kept-old-versions 2 ; And cleanup even more version-control t ; Version them backups delete-by-moving-to-trash t ; Dont delete, send to trash instead ;; startup inhibit-startup-screen t ; I have already done the tutorial. Twice inhibit-startup-message t ; I know I am ready inhibit-startup-echo-area-message t ; Yep, still know it initial-scratch-message nil ; I know it is the scratch buffer! initial-buffer-choice nil inhibit-startup-buffer-menu t inhibit-x-resources t initial-major-mode 'fundamental-mode pgtk-wait-for-event-timeout 0.001 ; faster child frames ad-redefinition-action 'accept ; dont care about legacy things being redefined inhibit-compacting-font-caches t ;; tabs tab-width 4 ; Always tab 4 spaces. indent-tabs-mode nil ; Never use actual tabs. ;; rendering cursor-in-non-selected-windows nil ; dont render cursors other windows ;; packages use-package-always-defer t load-prefer-newer t default-input-method nil use-dialog-box nil use-file-dialog nil use-package-expand-minimally t package-enable-at-startup nil use-package-enable-imenu-support t auto-mode-case-fold nil ; No second pass of case-insensitive search over auto-mode-alist. package-archives '(("melpa" . "https://melpa.org/packages/") ("gnu" . "https://elpa.gnu.org/packages/") ("nongnu" . "https://elpa.nongnu.org/nongnu/") ("melpa-stable" . "https://stable.melpa.org/packages/")) package-archive-priorities '(("gnu" . 99) ("nongnu" . 80) ("melpa" . 70) ("melpa-stable" . 50)) ) ;;; early-init.el ends here #+END_SRC ** =generated/.config/emacs/init.el= This contaions emacs #+BEGIN_SRC el :tangle generated/.config/emacs/init.el :noweb yes :mkdirp yes :eval never ;;; package --- Summary - My minimal Emacs init file -*- lexical-binding: t -*- ;;; Commentary: ;;; Simple Emacs setup I carry everywhere ;;; Code: (setq custom-file (locate-user-emacs-file "custom.el")) (load custom-file 'noerror) ;; no error on missing custom file (require 'package) (package-initialize) (defun reset-custom-vars () "Resets the custom variables that were set to crazy numbers" (setopt gc-cons-threshold (* 1024 1024 100)) (setopt garbage-collection-messages t)) (use-package emacs :custom (native-comp-async-query-on-exit t) (read-answer-short t) (use-short-answers t) (enable-recursive-minibuffers t) (which-func-update-delay 1.0) (visible-bell nil) (custom-buffer-done-kill t) (whitespace-line-column nil) (x-underline-at-descent-line t) (imenu-auto-rescan t) (uniquify-buffer-name-style 'forward) (confirm-nonexistent-file-or-buffer nil) (create-lockfiles nil) (make-backup-files nil) (kill-do-not-save-duplicates t) (sentence-end-double-space nil) (treesit-enabled-modes t) :init ;; base visual (menu-bar-mode -1) ;; no menu bar (toggle-scroll-bar -1) ;; no scroll bar (tool-bar-mode -1) ;; no tool bar either (blink-cursor-mode -1) ;; stop blinking ;; font of the century (set-frame-font "Aporetic Sans Mono 12" nil t) :bind (("C-" . pixel-scroll-precision) ; dont zoom in please, just scroll ("C-" . pixel-scroll-precision) ; dont zoom in either, just scroll ("C-x k" . kill-current-buffer)) ; kill the buffer, dont ask :hook (text-mode . delete-trailing-whitespace-mode) (prog-mode . delete-trailing-whitespace-mode) (after-init . global-display-line-numbers-mode) ;; always show line numbers (after-init . column-number-mode) ;; column number in the mode line (after-init . size-indication-mode) ;; file size in the mode line (after-init . pixel-scroll-precision-mode) ;; smooth mouse scroll (after-init . electric-pair-mode) ;; i mean ... parens should auto create (after-init . reset-custom-vars) ) (use-package autorevert :ensure nil :custom (auto-revert-interval 3) (auto-revert-remote-files nil) (auto-revert-use-notify t) (auto-revert-avoid-polling nil) (auto-revert-verbose t) :hook (after-init . global-auto-revert-mode)) (use-package recentf :ensure nil :commands (recentf-mode recentf-cleanup) :hook (after-init . recentf-mode) :custom (recentf-auto-cleanup 'never) (recentf-exclude (list "\\.tar$" "\\.tbz2$" "\\.tbz$" "\\.tgz$" "\\.bz2$" "\\.bz$" "\\.gz$" "\\.gzip$" "\\.xz$" "\\.zip$" "\\.7z$" "\\.rar$" "COMMIT_EDITMSG\\'" "\\.\\(?:gz\\|gif\\|svg\\|png\\|jpe?g\\|bmp\\|xpm\\)$" "-autoloads\\.el$" "autoload\\.el$")) :config ;; A cleanup depth of -90 ensures that `recentf-cleanup' runs before ;; `recentf-save-list', allowing stale entries to be removed before the list ;; is saved by `recentf-save-list', which is automatically added to ;; `kill-emacs-hook' by `recentf-mode'. (add-hook 'kill-emacs-hook #'recentf-cleanup -90)) (use-package savehist :ensure nil :commands (savehist-mode savehist-save) :hook (after-init . savehist-mode) :custom (savehist-autosave-interval 600) (savehist-additional-variables '(kill-ring ; clipboard register-alist ; macros mark-ring global-mark-ring ; marks search-ring regexp-search-ring))) (use-package hl-line :ensure nil :custom (hl-line-sticky-flag nil) (global-hl-line-sticky-flag nil) :hook (after-init . global-hl-line-mode)) (use-package saveplace :ensure nil :commands (save-place-mode save-place-local-mode) :hook (after-init . save-place-mode) :custom (save-place-limit 400)) (use-package nerd-icons :custom ;; disable bright icon colors (nerd-icons-color-icons nil))hells.nix (use-package doom-modeline :custom (inhibit-compacting-font-caches t) ;; speed (doom-modeline-buffer-file-name-style 'relative-from-project) (doom-modeline-major-mode-icon nil) ;; distracting icons, no thank you (doom-modeline-buffer-encoding nil) ;; everything is utf-8 anyway (doom-modeline-buffer-state-icon nil) ;; the filename already shows me (doom-modeline-lsp nil) ;; lsp state is too distracting, too often :hook (after-init . doom-modeline-mode)) (load-theme 'catppuccin :no-confirm) (use-package diminish :demand t) ;; declutter the modeline (use-package eldoc :diminish eldoc-mode :custom (eldoc-echo-area-use-multiline-p nil)) ;; docs for everything (use-package eldoc-box :defer t :config (set-face-background 'eldoc-box-border (catppuccin-color 'green)) (set-face-background 'eldoc-box-body (catppuccin-color 'base)) :bind (("M-h" . eldoc-box-help-at-point))) (use-package pulsar :commands pulsar-global-mode pulsar-recenter-top pulsar-reveal-entry :init (defface pulsar-catppuccin `((default :extend t) (((class color) (min-colors 88) (background light)) :background ,(catppuccin-color 'sapphire)) (((class color) (min-colors 88) (background dark)) :background ,(catppuccin-color 'sapphire)) (t :inverse-video t)) "Alternative nord face for `pulsar-face'." :group 'pulsar-faces) :custom (pulsar-face 'pulsar-catppuccin) :hook (after-init . pulsar-global-mode)) (use-package which-key :commands which-key-mode :diminish which-key-mode :hook (after-init . which-key-mode)) (use-package expreg :bind ("M-m" . expreg-expand)) (use-package vundo) ;; undo tree ;; better structured editing (use-package puni :commands puni-global-mode :hook (after-init . puni-global-mode)) (use-package avy :bind ("M-i" . avy-goto-char-2) :custom (avy-background t)) (use-package consult :bind ("C-x b" . consult-buffer) ;; orig. switch-to-buffer ("M-y" . consult-yank-pop) ;; orig. yank-pop ("M-g M-g" . consult-goto-line) ;; orig. goto-line ("M-g i" . consult-imenu) ;; consult version is interactive ("M-g r" . consult-ripgrep) ;; find in project also works :custom (consult-narrow-key "<")) (use-package vertico :commands vertico-mode :custom (read-file-name-completion-ignore-case t) (read-buffer-completion-ignore-case t) (completion-ignore-case t) (enable-recursive-minibuffers t) (minibuffer-prompt-properties '(read-only t cursor-intangible t face minibuffer-prompt)) :init (vertico-mode) :hook (minibuffer-setup-hook . cursor-intangible-mode)) (use-package marginalia :commands marginalia-mode :hook (after-init . marginalia-mode)) (use-package crux :bind ("C-c M-e" . crux-find-user-init-file) ("C-c C-w" . crux-transpose-windows) ("C-c M-d" . crux-find-current-directory-dir-locals-file) ("C-a" . crux-move-beginning-of-line)) (use-package magit :bind (("C-M-g" . magit-status))) (use-package nerd-icons-corfu :commands nerd-icons-corfu-formatter :defines corfu-margin-formatters) (use-package corfu :commands global-corfu-mode :custom (corfu-cycle t) (corfu-auto t) (corfu-auto-delay 1) (corfu-auto-prefix 3) (corfu-separator ?_) :hook (after-init . global-corfu-mode) :config (add-to-list 'corfu-margin-formatters #'nerd-icons-corfu-formatter)) (use-package cape) (use-package orderless :custom (completion-styles '(orderless partial-completion basic)) (completion-category-defaults nil) (completion-category-overrides nil)) (use-package yasnippet :commands yas-global-mode :diminish yas-minor-mode :hook (after-init . yas-global-mode)) (use-package yasnippet-snippets :after yasnippet) (use-package exec-path-from-shell :commands exec-path-from-shell-initialize :custom (exec-path-from-shell-arguments nil) :hook (after-init . exec-path-from-shell-initialize)) (use-package nixpkgs-fmt :custom (nixpkgs-fmt-command "nixfmt")) (use-package eat :bind (("C-c e p" . eat-project) ("C-c e t" . eat))) (use-package f :demand t) (use-package envrc :commands envrc-global-mode :hook (after-init . envrc-global-mode)) (use-package gptel :commands gptel-make-anthropic f-read-text :config (gptel-make-anthropic "Claude" :stream t :key (f-read-text "/run/secrets/claude_key"))) (use-package sideline-flymake) (use-package sideline-eglot) (use-package sideline :custom (sideline-backends-right '(sideline-flymake sideline-eglot)) :hook (eglot-managed-mode . sideline-mode) (flymake-mode . sideline-mode)) (use-package eglot :custom (eglot-extend-to-xref t) (eglot-ignored-server-capabilities '(:inlayHintProvider)) (jsonrpc-event-hook nil) :hook (eglot-managed-mode . eldoc-box-hover-mode) (before-save . eldoc-format-buffer) :bind (:map eglot-mode-map ("C-c l a" . eglot-code-actions) ("C-c l r" . eglot-rename) ("C-c l h" . eldoc) ("C-c l g" . xref-find-references) ("C-c l w" . eglot-reconnect))) (use-package proced :custom (proced-auto-update-flag t) (proced-auto-update-interval 3) (proced-enable-color-flag t) (proced-show-remote-processes t)) (use-package org :ensure t :defer t :commands (org-mode org-capture org-agenda) :init (defvar org-journal-file "~/nextcloud/org/journal.org") (defvar org-archive-file "~/nextcloud/org/archive.org") (defvar org-notes-file "~/nextcloud/org/notes.org") (defvar org-inbox-file "~/nextcloud/org/inbox.org") (defvar org-work-file "~/nextcloud/org/work.org") (defun my/org-capture-project-target-heading () "Determine Org target headings from the current file's project path. This function assumes a directory structure like '~/projects/COMPANY/PROJECT/'. It extracts 'COMPANY' and 'PROJECT' to use as nested headlines for an Org capture template. If the current buffer is not visi ting a file within such a project structure, it returns nil, causing capture to default to the top of the file." (when-let* ((path (buffer-file-name))) ; Ensure we are in a file-visiting buffer (let ((path-parts (split-string path "/" t " "))) (when-let* ((projects-pos (cl-position "projects" path-parts :test #'string=)) (company (nth (+ 1 projects-pos) path-parts)) (project (nth (+ 2 projects-pos) path-parts))) ;; Return a list of headlines for Org to find or create. (list company project))))) :bind (("C-c c" . org-capture) ("C-c i" . org-store-link) ("C-c a" . org-agenda) :map org-mode-map ("C-c t" . org-toggle-inline-images) ("C-c l" . org-toggle-link-display)) :custom (org-agenda-files (list org-inbox-file org-journal-file)) (org-directory "~/nextcloud/org") (org-default-notes-file org-inbox-file) (org-archive-location (concat org-archive-file "::* From %s")) (org-log-done 'time) (org-log-into-drawer t) (org-hide-emphasis-markers t) (org-src-fontify-natively t) (org-src-tab-acts-natively t) (org-capture-templates '(("t" "Todo" entry (file org-inbox-file) "* TODO %?\n:PROPERTIES:\n:CREATED: %U\n:END:\n\n%a\n\n)") ("j" "Journal" entry (file+olp+datetree org-journal-file) "* %?\n:PROPERTIES:\n:CREATED: %U\n:END:\n\n%a\n\n") ("n" "Note" entry (file org-notes-file) "* %?\n:PROPERTIES:\n:CREATED: %U\n:END:\n\n%a\n\n") ("p" "Project Task" item (file+function org-work-file my/org-capture-project-target-heading) "* TODO %? \n CLOCK: %U" )) ) :config ;; Enable syntax highlighting in code blocks (add-hook 'org-mode-hook 'turn-on-font-lock) (add-hook 'org-mode-hook 'org-indent-mode)) ;; extras (use-package comp-run :ensure nil :config (push "tramp-loaddefs.el.gz" native-comp-jit-compilation-deny-list) (push "cl-loaddefs.el.gz" native-comp-jit-compilation-deny-list)) (use-package rustic :custom (rustic-lsp-client 'eglot)) (provide 'init) ;;; init.el ends here #+END_SRC ** =generated/.config/hypr/animations.conf= These are config files for .config/hypr #+BEGIN_SRC conf :tangle generated/.config/hypr/animations.conf :noweb yes :mkdirp yes :eval never animations { enabled = yes bezier = myBezier, 0.05, 0.9, 0.1, 1.05 animation = windows, 1, 7, myBezier animation = windowsOut, 1, 7, default, popin 80% animation = border, 1, 10, default animation = borderangle, 1, 8, default animation = fade, 1, 7, default animation = workspaces, 1, 6, default } #+END_SRC ** =generated/.config/hypr/behaviour.conf= These are config files for .config/hypr #+BEGIN_SRC conf :tangle generated/.config/hypr/behaviour.conf :noweb yes :exports code :wrap nil :mkdirp yes :eval never # Keyboard and mouse settings input { numlock_by_default = true touchpad { natural_scroll = true tap-to-click = true drag_lock = true } } # Scrolling modifier settings # Touchpad settings (applies to all touchpads) # Focus settings # Miscellaneous settings #+END_SRC ** =generated/.config/hypr/bindings.conf= These are config files for .config/hypr #+BEGIN_SRC conf :tangle generated/.config/hypr/bindings.conf :noweb yes :mkdirp yes :eval never $mainMod = SUPER # launcher / kill / reload bind = $mainMod, Space, exec, ~/.config/scripts/wofi-launcher.sh bind = ALT, Space, exec, ~/.config/scripts/wofi-launcher.sh bind = $mainMod, Q, killactive, bind = $mainMod SHIFT, Q, exit, bind = $mainMod SHIFT, R, exec, hyprctl reload bind = $mainMod, X , exec, qs -c powermenu bind = $mainMod, L, exec, hyprlock # grimblast # bind = $mainMod SHIFT, P, exec, grimblast -n -f copysave active # bind = $mainMod SHIFT, S, exec, grimblast -n -f copysave area # bind = , XF86Screenshot, exec, grimblast -n -f copysave area # bind = $mainMod ALT, P, exec, grimblast -n -f copysave output # bind = $mainMod CTRL, P, exec, grimblast -n -f copysave screen # Flameshot keybindings bind = $mainMod SHIFT, P, exec, flameshot full -p ~/Pictures/Screenshots -c bind = $mainMod SHIFT, S, exec, flameshot gui bind = , XF86Screenshot, exec, flameshot gui bind = $mainMod ALT, P, exec, flameshot full -d 5000 -p ~/Pictures/Screenshots -c bind = $mainMod CTRL, P, exec, flameshot screen -n 0 -p ~/Pictures/Screenshots -c # Switch windows bind = ALT, TAB, cyclenext, prev bind = ALT SHIFT, TAB, cyclenext, prev bind = ALT, mouse_down, cyclenext, prev bind = ALT , mouse_up, cyclenext, prev bindel = CTRL ALT, mouse_up, layoutmsg, addmaster bindel = CTRL ALT, mouse_down, layoutmsg, removemaster bind = CTRL ALT, right, layoutmsg, colwidth +conf bind = CTRL ALT, left, layoutmsg, colwidth -conf # switch layouts # Hyprscrolling bind = $mainMod, period, layoutmsg, move +col bind = $mainMod, comma, layoutmsg, swapcol l # Column resize bind = $mainMod SHIFT, period, layoutmsg, colresize +conf bind = $mainMod SHIFT, comma, layoutmsg, colresize -conf # Make / break a tab-group (stack) bind = $mainMod, S, togglegroup # Cycle tabs in the group bind = $mainMod, bracketright, changegroupactive, f bind = $mainMod, bracketleft, changegroupactive, b bind = $mainMod, T, exec, ~/.config/scripts/layout-selector.sh # Focus movement bind = $mainMod, H, movefocus, l bind = $mainMod, L, movefocus, r bind = $mainMod, K, movefocus, u bind = $mainMod, J, movefocus, d bind = $mainMod, left, movefocus, l bind = $mainMod, right, movefocus, r bind = $mainMod, up, movefocus, u bind = $mainMod, down, movefocus, d # Move windows bind = $mainMod SHIFT, H, movewindow, l bind = $mainMod SHIFT, L, movewindow, r bind = $mainMod SHIFT, K, movewindow, u bind = $mainMod SHIFT, J, movewindow, d bind = $mainMod SHIFT, left, movewindow, l bind = $mainMod SHIFT, right, movewindow, r bind = $mainMod SHIFT, up, movewindow, u bind = $mainMod SHIFT, down, movewindow, d # Resize windows bind = $mainMod CTRL, H, resizeactive, -30 0 bind = $mainMod CTRL, L, resizeactive, 30 0 bind = $mainMod CTRL, K, resizeactive, 0 -30 bind = $mainMod CTRL, J, resizeactive, 0 30 # Floating / fullscreen bind = $mainMod, V, togglefloating, bind = $mainMod, F, fullscreen, 0 bind = $mainMod SHIFT, F, fullscreen, 1 # Workspaces bind = $mainMod, 1, workspace, 1 bind = $mainMod, 2, workspace, 2 bind = $mainMod, 3, workspace, 3 bind = $mainMod, 4, workspace, 4 bind = $mainMod, 5, workspace, 5 bind = $mainMod, 6, workspace, 6 bind = $mainMod, 7, workspace, 7 bind = $mainMod, 8, workspace, 8 bind = $mainMod, 9, workspace, 9 bind = $mainMod, 0, workspace, 10 bind = $mainMod SHIFT, 1, movetoworkspace, 1 bind = $mainMod SHIFT, 2, movetoworkspace, 2 bind = $mainMod SHIFT, 3, movetoworkspace, 3 bind = $mainMod SHIFT, 4, movetoworkspace, 4 bind = $mainMod SHIFT, 5, movetoworkspace, 5 bind = $mainMod SHIFT, 6, movetoworkspace, 6 bind = $mainMod SHIFT, 7, movetoworkspace, 7 bind = $mainMod SHIFT, 8, movetoworkspace, 8 bind = $mainMod SHIFT, 9, movetoworkspace, 9 bind = $mainMod SHIFT, 0, movetoworkspace, 10 # Cycle workspaces bind = $mainMod, mouse_down, workspace, e+1 bind = $mainMod, mouse_up, workspace, e-1 # Mouse drag bindm = $mainMod, mouse:272, movewindow bindm = $mainMod, mouse:273, resizewindow ######################### # Audio (pamixer) ######################### bind = , XF86AudioRaiseVolume, exec, pamixer -i 5 bind = , XF86AudioLowerVolume, exec, pamixer -d 5 bind = , XF86AudioMute, exec, pamixer -t bind = , XF86AudioMicMute, exec, pamixer --default-source -t ######################### # Media (playerctl) ######################### bind = , XF86AudioPlay, exec, playerctl play-pause bind = , XF86AudioPause, exec, playerctl pause bind = , XF86AudioNext, exec, playerctl next bind = , XF86AudioPrev, exec, playerctl previous bind = , XF86AudioStop, exec, playerctl stop ######################### # Brightness (brightnessctl) ######################### bind = , XF86MonBrightnessUp, exec, brightnessctl set +10% bind = , XF86MonBrightnessDown, exec, brightnessctl set 10%- bind = , XF86KbdBrightnessUp, exec, brightnessctl -d '*kbd_backlight*' set +10% bind = , XF86KbdBrightnessDown, exec, brightnessctl -d '*kbd_backlight*' set 10%- ######################### # Power / session ######################### bind = , XF86Sleep, exec, systemctl suspend bind = , XF86PowerOff, exec, systemctl poweroff bind = , XF86WakeUp, exec, systemctl suspend bind = CTRL ALT, L, exec, loginctl lock-session ######################### # Start apps ######################### bind = $mainMod, E, exec, thunar bind = $mainMod, RETURN, exec, kitty bind = CTRL ALT, B, exec, flatpak run eu.betterbird.Betterbird bind = CTRL ALT, S, exec, spotify bind = $mainMod, Z, exec, zeditor bind = $mainMod, W, exec, zen bind = CTRL ALT, T, exec, solidtime-desktop ######################### # Auto apps ######################### bind = , workspace, exec, ~/.config/scripts/set-workspace-wallpaper.sh ######################### # System stuff ######################### bind = $mainMod, U, exec, kitty -e bash -lc "$HOME/.config/scripts/update.sh" #+END_SRC ** =generated/.config/hypr/exec-once.conf= These are config files for .config/hypr #+BEGIN_SRC conf :tangle generated/.config/hypr/exec-once.conf :noweb yes :mkdirp yes :eval never exec-once = dbus-update-activation-environment --systemd --all exec-once = hypridle exec-once = systemd-run --user --scope --unit=elephant elephant exec-once = waybar exec-once = awww-daemon exec-once = awww img ~/Wallpapers/pictures/01.jpg exec-once = ~/.config/scripts/set-workspace-wallpaper.sh exec-once = ~/.config/scripts/workspace-listener.sh exec-once = /run/current-system/sw/libexec/polkit-gnome-authentication-agent-1 exec-once = nextcloud --background exec-once = dbus-update-activation-environment --systemd WAYLAND_DISPLAY XDG_CURRENT_DESKTOP exec-once = flameshot #+END_SRC ** =generated/.config/hypr/hypridle.conf= These are config files for .config/hypr #+BEGIN_SRC conf :tangle generated/.config/hypr/hypridle.conf :noweb yes :mkdirp yes :eval never general { lock_cmd = hyprlock before_sleep_cmd = hyprlock after_sleep_cmd = hyprctl dispatch dpms on ignore_dbus_inhibit = false } listener { timeout = 600 on-timeout = hyprlock } listener { timeout = 900 on-timeout = hyprctl dispatch dpms off on-resume = hyprctl dispatch dpms on } listener { timeout = 1200 on-timeout = systemctl suspend } #+END_SRC ** =generated/.config/hypr/hyprlock.conf= These are config files for .config/hypr #+BEGIN_SRC conf :tangle generated/.config/hypr/hyprlock.conf :noweb yes :mkdirp yes :eval never general { grace = 2 hide_cursor = true } background { monitor = path = screenshot blur_passes = 3 blur_size = 8 } input-field { monitor = size = 250, 50 position = 0, -80 outline_thickness = 2 dots_center = true fade_on_empty = false } #+END_SRC ** =generated/.config/hypr/hyprland.conf= These are config files for .config/hypr #+BEGIN_SRC conf :tangle generated/.config/hypr/hyprland.conf :noweb yes :mkdirp yes :eval never source = ./theming.conf source = ./animations.conf source = ./bindings.conf source = ./behaviour.conf source = ./exec-once.conf source = ./layer-rules.conf source = ./layout.conf source = ./monitor-rules.conf source = ./window-rules.conf source = ./workspace-rules.conf #+END_SRC ** =generated/.config/hypr/layer-rules.conf= These are config files for .config/hypr #+BEGIN_SRC conf :tangle generated/.config/hypr/layer-rules.conf :noweb yes :mkdirp yes :eval never layerrule = blur on, ignore_alpha 1, match:namespace waybar layerrule = xray 1, match:namespace waybar #+END_SRC ** =generated/.config/hypr/layout.conf= These settings control Hyprland config #+BEGIN_SRC conf :tangle generated/.config/hypr/layout.conf :noweb yes :mkdirp yes :eval never scrolling { fullscreen_on_one_column = true column_width = 0.32 # default: 3 windows side by side explicit_column_widths = 0.329, 0.5, 0.667, 1.0 } #+END_SRC ** =generated/.config/hypr/monitor-rules.conf= These are config files for .config/hypr #+BEGIN_SRC conf :tangle generated/.config/hypr/monitor-rules.conf :noweb yes :mkdirp yes :eval never monitor = DP-1, preferred, 0x0, 1 monitor = eDP-1, preferred, auto-left, 1.5 #+END_SRC ** =generated/.config/hypr/theming.conf= These are config files for .config/hypr #+BEGIN_SRC conf :tangle generated/.config/hypr/theming.conf :noweb yes :mkdirp yes :eval never # Hyprland Catppuccin Mocha Theme (solid colors) # Colors $base = #1e1e2e $baseshadow = #1e1e2e99 $mantle = #181825 $surface0 = #313244 $surface1 = #45475a $surface2 = #585b70 $text = #cdd6f4 $rosewater = #f5e0dc $lavender = #b4befe $red = #f38ba8 $peach = #fab387 $yellow = #f9e2af $green = #a6e3a1 $teal = #94e2d5 $blue = #89b4fa $mauve = #cba6f7 $flamingo = #f2cdcd $inactive = #595959aa # General general { gaps_in = 2 gaps_out = 4 border_size = 4 resize_on_border = true extend_border_grab_area = 20 col.active_border = rgb(89b4fa) rgb(a6e3a1) 45deg col.inactive_border = rgba(595959aa) } # Decorations decoration { rounding = 8 shadow { color = rgba(1e1e2e99) } } # Groups group { col.border_active = rgb(89b4fa) col.border_inactive = rgb(45475a) col.border_locked_active = rgb(94e2d5) groupbar { col.active = rgb(89b4fa) col.inactive = rgb(45475a) text_color = rgb(cdd6f4) } } # Misc misc { background_color = rgb(1e1e2e) } #+END_SRC ** =generated/.config/hypr/window-rules.conf= These are config files for .config/hypr #+BEGIN_SRC conf :tangle generated/.config/hypr/window-rules.conf :noweb yes :mkdirp yes :eval never # Network Manager editor windowrule { name = Network-Manager-editor match:class = nm-connection-editor float = on move = move onscreen 100%-w 0 size = 900 700 } # PulseAudio Volume Control windowrule { name = pavucontrol match:class = org.pulseaudio.pavucontrol float = on move = move onscreen 100%-w 0 size = 900 700 } # Blueman Manager windowrule { name = blueman match:class = .blueman-manager-wrapped float = on move = move onscreen 100%-w 0 size = 900 700 } #Quickshell powermenu windowrule { name = quickshell-powermenu match:title = quickshell-powermenu opacity = 1.0 0.8 float = on move = cursor -50% 0 pin = on } #Quickshell media menu windowrule { name = quickshell-media match:title = quickshell-media float = on move = cursor -50% 0 pin = on } # Wofi window rules # (match: fields do not support $variables, hardcoded intentionally) windowrule { name = wofi match:class = ^(wofi)$ border_color = rgb(89b4fa) rgb(a6e3a1) 45deg rounding = 14 } #+END_SRC ** =generated/.config/hypr/workspace-rules.conf= These setttings configure rules for workspaces #+BEGIN_SRC conf :tangle generated/.config/hypr/workspace-rules.conf :noweb yes :mkdirp yes :eval never workspace = 1, monitor:eDP-1, layout:master workspace = 2, monitor:eDP-1, layout:monocle workspace = 3, monitor:eDP-1, layout:master workspace = 4, monitor:DP-1, layout:scrolling workspace = 5, monitor:DP-1, layout:dwindle workspace = 6, monitor:DP-1, layout:dwindle #+END_SRC ** =generated/.config/quickshell/media/shell.qml= offers a adio widget #+BEGIN_SRC qml :tangle generated/.config/quickshell/media/shell.qml :noweb yes :mkdirp yes :eval never import Quickshell import Quickshell.Io import QtQuick import QtQuick.Layouts ShellRoot { QtObject { id: colors readonly property color baseAlpha: Qt.rgba(30/255, 30/255, 46/255, 0.95) readonly property color base: "#1e1e2e" readonly property color surface0: "#313244" readonly property color surface1: "#45475a" readonly property color surface2: "#585b70" readonly property color text: "#cdd6f4" readonly property color subtext0: "#a6adc8" readonly property color subtext1: "#bac2de" readonly property color blue: "#89b4fa" readonly property color green: "#a6e3a1" readonly property color teal: "#94e2d5" readonly property color red: "#f38ba8" readonly property color mauve: "#cba6f7" readonly property color peach: "#fab387" readonly property color lavender: "#b4befe" } QtObject { id: media property string artist: "" property string title: "" property string album: "" property string artUrl: "" property string status: "" property string device: "" property string player: "" property real progress: 0.0 property real duration: 0.0 property real position: 0.0 property int shuffleMode: 0 readonly property bool isSpotify: player.indexOf("spotify") !== -1 } Timer { interval: 1000 running: true repeat: true onTriggered: { playerProc.running = true artistProc.running = true titleProc.running = true albumProc.running = true artProc.running = true statusProc.running = true positionProc.running = true lengthProc.running = true if (media.isSpotify) shuffleProc.running = true } } Process { id: playerProc command: ["playerctl", "-l"] stdout: StdioCollector { onStreamFinished: { var lines = text.trim().split("\n") for (var i = 0; i < lines.length; i++) { if (lines[i].indexOf("spotify") !== -1) { media.player = lines[i].trim() return } } media.player = lines[0] ? lines[0].trim() : "" } } } Process { id: artistProc command: ["playerctl", "metadata", "artist"] stdout: StdioCollector { onStreamFinished: media.artist = text.trim() } } Process { id: titleProc command: ["playerctl", "metadata", "title"] stdout: StdioCollector { onStreamFinished: media.title = text.trim() } } Process { id: albumProc command: ["playerctl", "metadata", "album"] stdout: StdioCollector { onStreamFinished: media.album = text.trim() } } Process { id: artProc command: ["playerctl", "metadata", "mpris:artUrl"] stdout: StdioCollector { onStreamFinished: media.artUrl = text.trim() } } Process { id: statusProc command: ["playerctl", "status"] stdout: StdioCollector { onStreamFinished: media.status = text.trim() } } Process { id: positionProc command: ["playerctl", "position"] stdout: StdioCollector { onStreamFinished: { media.position = parseFloat(text.trim()) || 0 if (media.duration > 0) media.progress = media.position / media.duration } } } Process { id: lengthProc command: ["playerctl", "metadata", "mpris:length"] stdout: StdioCollector { onStreamFinished: { media.duration = (parseFloat(text.trim()) || 0) / 1000000 } } } Process { id: shuffleProc command: ["playerctl", "--player=" + media.player, "shuffle"] stdout: StdioCollector { onStreamFinished: { media.shuffleMode = (text.trim() === "On") ? 1 : 0 } } } Process { id: shuffleOnProc; command: ["playerctl", "--player=" + media.player, "shuffle", "on"] } Process { id: shuffleOffProc; command: ["playerctl", "--player=" + media.player, "shuffle", "off"] } function cycleShuffleMode() { var next = (media.shuffleMode + 1) % 2 media.shuffleMode = next if (next === 0) shuffleOffProc.running = true else shuffleOnProc.running = true } // Focus spotify — uses exact lowercase class as reported by hyprctl Process { id: focusSpotifyProc command: ["hyprctl", "dispatch", "focuswindow", "class:^(spotify)$"] } function focusPlayer() { if (media.isSpotify) { focusSpotifyProc.running = true } } Process { id: prevProc; command: ["playerctl", "previous"] } Process { id: playProc; command: ["playerctl", "play-pause"] } Process { id: nextProc; command: ["playerctl", "next"] } FloatingWindow { id: root title: "quickshell-media" visible: true implicitWidth: 300 implicitHeight: 420 color: "transparent" Shortcut { sequence: "Escape" onActivated: Qt.quit() } // Gradient border — hidden when app has focus Rectangle { anchors.fill: parent anchors.margins: -2 radius: 18 z: -1 opacity: Qt.application.active ? 0 : 1 Behavior on opacity { NumberAnimation { duration: 150 } } gradient: Gradient { orientation: Gradient.Horizontal GradientStop { position: 0.0; color: colors.blue } GradientStop { position: 1.0; color: colors.green } } } Rectangle { anchors.fill: parent radius: 16 color: colors.base ColumnLayout { anchors { fill: parent margins: 16 } spacing: 12 // Album art — click to focus player Rectangle { Layout.fillWidth: true Layout.preferredHeight: 200 radius: 12 color: colors.surface0 clip: true Image { anchors.fill: parent source: media.artUrl fillMode: Image.PreserveAspectCrop visible: media.artUrl !== "" } Text { anchors.centerIn: parent text: "󰝚" font.pixelSize: 48 color: colors.surface2 visible: media.artUrl === "" } MouseArea { anchors.fill: parent cursorShape: Qt.PointingHandCursor onClicked: focusPlayer() } } // Artist Text { Layout.fillWidth: true text: media.artist || "Unknown artist" color: colors.subtext1 font.pixelSize: 12 elide: Text.ElideRight } // Title Text { Layout.fillWidth: true text: media.title || "Nothing playing" color: colors.text font.pixelSize: 14 font.bold: true elide: Text.ElideRight } // Album Text { Layout.fillWidth: true text: media.album color: colors.subtext0 font.pixelSize: 11 elide: Text.ElideRight visible: media.album !== "" } // Device (Spotify) Text { Layout.fillWidth: true text: "󰓻 " + media.device color: colors.green font.pixelSize: 11 visible: media.device !== "" } // Progress bar Rectangle { Layout.fillWidth: true height: 4 radius: 2 color: colors.surface1 Rectangle { width: parent.width * media.progress height: parent.height radius: parent.radius gradient: Gradient { orientation: Gradient.Horizontal GradientStop { position: 0.0; color: colors.blue } GradientStop { position: 1.0; color: colors.green } } } } // Time RowLayout { Layout.fillWidth: true Text { text: { var m = Math.floor(media.position / 60) var s = Math.floor(media.position % 60) return m + ":" + (s < 10 ? "0" + s : s) } color: colors.subtext0 font.pixelSize: 11 } Item { Layout.fillWidth: true } Text { text: { var m = Math.floor(media.duration / 60) var s = Math.floor(media.duration % 60) return m + ":" + (s < 10 ? "0" + s : s) } color: colors.subtext0 font.pixelSize: 11 } } // Playback controls + shuffle RowLayout { Layout.fillWidth: true Layout.alignment: Qt.AlignHCenter spacing: 20 // Shuffle button (Spotify only) Item { visible: media.isSpotify width: 28 height: 28 Text { anchors.centerIn: parent text: "󰒟" font.pixelSize: 18 color: media.shuffleMode === 0 ? colors.surface2 : colors.blue } MouseArea { anchors.fill: parent cursorShape: Qt.PointingHandCursor onClicked: cycleShuffleMode() } } Text { text: "󰒮" font.pixelSize: 22 color: prevHover.containsMouse ? colors.blue : colors.text MouseArea { id: prevHover anchors.fill: parent hoverEnabled: true cursorShape: Qt.PointingHandCursor onClicked: prevProc.running = true } } Text { text: media.status === "Playing" ? "󰏤" : "󰐊" font.pixelSize: 28 color: playHover.containsMouse ? colors.green : colors.text MouseArea { id: playHover anchors.fill: parent hoverEnabled: true cursorShape: Qt.PointingHandCursor onClicked: playProc.running = true } } Text { text: "󰒭" font.pixelSize: 22 color: nextHover.containsMouse ? colors.blue : colors.text MouseArea { id: nextHover anchors.fill: parent hoverEnabled: true cursorShape: Qt.PointingHandCursor onClicked: nextProc.running = true } } } } } } } #+END_SRC ** =generated/.config/quickshell/powermenu/shell.qml= Provides a powermenu #+BEGIN_SRC qml :tangle generated/.config/quickshell/powermenu/shell.qml :noweb yes :mkdirp yes :eval never import Quickshell import Quickshell.Io import QtQuick import QtQuick.Layouts ShellRoot { QtObject { id: colors readonly property color baseAlpha: Qt.rgba(30/255, 30/255, 46/255, 0.9) readonly property color base: "#1e1e2e" readonly property color surface0: "#313244" readonly property color surface1: "#45475a" readonly property color surface2: "#585b70" readonly property color text: "#cdd6f4" readonly property color subtext0: "#a6adc8" readonly property color subtext1: "#bac2de" readonly property color blue: "#89b4fa" readonly property color green: "#a6e3a1" readonly property color teal: "#94e2d5" readonly property color red: "#f38ba8" readonly property color mauve: "#cba6f7" readonly property color peach: "#fab387" readonly property color lavender: "#b4befe" } FloatingWindow { id: root title: "quickshell-powermenu" visible: true width: 220 height: contentLayout.implicitHeight + 32 color: colors.base Shortcut { sequence: "Escape" onActivated: Qt.quit() } // Gradient border — hidden when app has focus Rectangle { anchors.fill: parent anchors.margins: -2 radius: 18 z: -1 opacity: Qt.application.active ? 0 : 1 Behavior on opacity { NumberAnimation { duration: 150 } } gradient: Gradient { orientation: Gradient.Horizontal GradientStop { position: 0.0; color: colors.blue } GradientStop { position: 1.0; color: colors.green } } } Rectangle { anchors.fill: parent radius: 16 color: colors.base ColumnLayout { id: contentLayout anchors { top: parent.top left: parent.left right: parent.right margins: 16 } spacing: 4 Text { text: " Power Menu" color: colors.text font.pixelSize: 13 font.bold: true Layout.bottomMargin: 8 } Repeater { model: [ { label: "󰌾 Lock", cmd: ["hyprlock"] }, { label: "󰐥 Shutdown", cmd: ["systemctl", "poweroff"] }, { label: "󰑙 Reboot", cmd: ["systemctl", "reboot"] }, { label: "󰍃 Logout", cmd: ["bash", "-c", "loginctl terminate-session $XDG_SESSION_ID"] }, { label: "󰒲 Hibernate", cmd: ["systemctl", "hibernate"] }, { label: "󰤄 Suspend", cmd: ["systemctl", "suspend"] }, ] delegate: Rectangle { id: item Layout.fillWidth: true height: 38 radius: 8 color: hovered ? colors.surface1 : colors.base property bool hovered: false Rectangle { anchors.fill: parent anchors.margins: -2 radius: parent.radius + 2 visible: item.hovered z: -1 gradient: Gradient { orientation: Gradient.Horizontal GradientStop { position: 0.0; color: colors.blue } GradientStop { position: 1.0; color: colors.green } } } Text { anchors.verticalCenter: parent.verticalCenter anchors.left: parent.left anchors.leftMargin: 12 text: modelData.label color: item.hovered ? colors.text : colors.subtext1 font.pixelSize: 13 } MouseArea { anchors.fill: parent hoverEnabled: true onEntered: item.hovered = true onExited: item.hovered = false onClicked: proc.running = true } Process { id: proc command: modelData.cmd onExited: Qt.quit() } } } Item { height: 4 } } } } } #+END_SRC ** =generated/.config/scripts/batterywarn.sh= Providing an media #+BEGIN_SRC sh :tangle generated/.config/scripts/batterywarn.sh :shebang "#!/usr/bin/env bash" :noweb yes :mkdirp yes :eval never capacity=$(cat /sys/class/power_supply/BAT*/capacity) status=$(cat /sys/class/power_supply/BAT*/status) if [ "$status" != "Charging" ] && [ "$capacity" -lt 15 ]; then echo " $capacity%" else echo "" fi #+END_SRC ** =generated/.config/scripts/media.sh= Providing an media #+BEGIN_SRC sh :tangle generated/.config/scripts/media.sh :shebang "#!/usr/bin/env bash" :noweb yes :mkdirp yes :eval never # Player selection — prefer actively playing player player=$(playerctl -l 2>/dev/null | while read -r p; do st=$(playerctl --player="$p" status 2>/dev/null) [ "$st" = "Playing" ] && echo "$p" && break done) [ -z "$player" ] && player=$(playerctl -l 2>/dev/null | head -n1) if [ -z "$player" ]; then jq -c -n '{text: "", tooltip: "", class: "inactive"}' exit 0 fi status=$(playerctl --player="$player" status 2>/dev/null) if [ "$status" != "Playing" ] && [ "$status" != "Paused" ]; then jq -c -n '{text: "", tooltip: "", class: "inactive"}' exit 0 fi artist=$(playerctl --player="$player" metadata artist 2>/dev/null) title=$(playerctl --player="$player" metadata title 2>/dev/null) album=$(playerctl --player="$player" metadata album 2>/dev/null) art=$(playerctl --player="$player" metadata mpris:artUrl 2>/dev/null) length=$(playerctl --player="$player" metadata mpris:length 2>/dev/null) position=$(playerctl --player="$player" position 2>/dev/null) # Progress percentage — pure bash, no bc needed if [ -n "$length" ] && [ -n "$position" ] && [ "$length" -gt 0 ] 2>/dev/null; then pos_us=$(echo "$position" | awk '{printf "%d", $1 * 1000000}') progress=$(( pos_us * 100 / length )) else progress=0 fi # Spotify device device="" if [[ "$player" == *"spotify"* ]]; then device=$(playerctl --player="$player" metadata xesam:url 2>/dev/null | grep -o 'device=[^&]*' | cut -d= -f2) fi # Icon if [ "$status" = "Paused" ]; then icon="⏸ " else icon="▶ " fi # Scrolling ticker CACHE_FILE="/tmp/waybar_media_scroll_${player//\//_}" full_text="${artist} — ${title}" text_len=${#full_text} display_len=30 # Reset scroll offset when track changes TRACK_FILE="/tmp/waybar_media_track_${player//\//_}" last_track="" [ -f "$TRACK_FILE" ] && last_track=$(cat "$TRACK_FILE") if [ "$full_text" != "$last_track" ]; then echo "0" > "$CACHE_FILE" echo "$full_text" > "$TRACK_FILE" fi if [ "$text_len" -le "$display_len" ]; then text="$full_text" else offset=0 [ -f "$CACHE_FILE" ] && offset=$(cat "$CACHE_FILE") padded="${full_text} ${full_text}" text="${padded:$offset:$display_len}" next_offset=$(( (offset + 1) % (text_len + 4) )) echo "$next_offset" > "$CACHE_FILE" fi # Build tooltip tooltip="Artist: ${artist} Title: ${title} Album: ${album}" if [ -n "$device" ]; then tooltip="${tooltip} 󰓻 ${device}" fi tooltip="${tooltip}" jq -c -n \ --arg text "${icon}${text}" \ --arg tooltip "$tooltip" \ --arg class "$player" \ --arg art "$art" \ '{text: $text, tooltip: $tooltip, class: $class, alt: $art}' #+END_SRC ** =generated/.config/scripts/layout-selector.sh= Choose your layout #+BEGIN_SRC bash :tangle generated/.config/scripts/layout-selector.sh :shebang "#!/usr/bin/env bash" :noweb yes :mkdirp yes :eval never # layout-selector.sh # Select a workspace layout using Wofi, shows description, applies with layoutmsg # Define layouts and descriptions declare -A LAYOUTS=( [dwindle]="舘 Dwindle: Auto-tiling, windows shrink progressively" [master]=" Master: One main window, others stacked" [scrolling]=" Scrolling: Vertical list, scroll through windows" [monocle]=" Monocle: One window fills the screen" [floating]=" Floating: Free move & resize" ) ORDER=(dwindle master scrolling monocle floating) # Prepare Wofi menu: show "layoutname: description" MENU_ITEMS=() for key in "${ORDER[@]}"; do MENU_ITEMS+=("$key: ${LAYOUTS[$key]}") done # Show selection menu via Wofi CHOICE=$(printf '%s\n' "${MENU_ITEMS[@]}" | wofi --dmenu --prompt "Select Layout") # Exit if cancelled [ -z "$CHOICE" ] && exit 0 # Extract layout name from selection (before colon) LAYOUT_NAME="${CHOICE%%:*}" # Apply layout via layoutmsg hyprctl dispatch layoutmsg setlayout "$LAYOUT_NAME" # Show OSD feedback hyprctl dispatch oSD "Layout: $LAYOUT_NAME" 2000 #+END_SRC ** =generated/.config/scripts/power.sh= Enables a terminal power menu #+BEGIN_SRC sh :tangle generated/.config/scripts/power.sh :shebang "#!/usr/bin/env bash" :noweb yes :mkdirp yes :eval never # # Launch a power menu # # Requires fzf and systemd (loginctl, systemctl) # # Author: Jesse Mirabel # Date: August 19, 2025 # License: MIT main() { local list=( "󰌾 Lock" "󰐥 Shutdown" "󰑙 Reboot" "󰍃 Logout" "󰒲 Hibernate" "󰤄 Suspend" ) local options=( "--border=sharp" "--border-label= Power Menu " "--cycle" "--ghost=Search" "--height=~100%" "--highlight-line" "--info=inline-right" "--pointer=" "--reverse" ) local selected selected=$(printf "%s\n" "${list[@]}" | fzf "${options[@]}") case $selected in Lock) loginctl lock-session ;; Shutdown) systemctl poweroff ;; Reboot) systemctl reboot ;; Logout) loginctl terminate-session "$XDG_SESSION_ID" ;; Hibernate) systemctl hibernate ;; Suspend) systemctl suspend ;; *) return 1 ;; esac } main #+END_SRC ** =generated/.config/scripts/update.sh= A file containing color variables #+BEGIN_SRC sh :tangle generated/.config/scripts/update.sh :shebang "#!/usr/bin/env bash" :noweb yes :mkdirp yes :eval never set -e REPO="/home/$USER/Repos/nixos/Droidnix" HOSTNAME="$(hostname)" cd "$REPO" echo "🔧 Fixing ownership..." sudo chown "$USER":"$USER" flake.lock 2>/dev/null || true echo "🔄 Updating flake..." nix flake update echo "🏗 Rebuilding NixOS..." sudo nixos-rebuild switch --flake ".#$HOSTNAME" echo "📦 Updating Flatpaks..." flatpak update -y #+END_SRC ** =generated/.config/scripts/wofi-launcher.sh= Providing an media #+BEGIN_SRC sh :tangle generated/.config/scripts/wofi-launcher.sh :shebang "#!/usr/bin/env bash" :noweb yes :mkdirp yes :eval never wofi --show drun \ --style ~/.config/wofi/style.css \ --no-actions \ --allow-images=false \ --columns 1 \ --prompt "Apps ..." #+END_SRC ** =generated/.config/shared/colors.css= A file containing color variables #+BEGIN_SRC css :tangle generated/.config/shared/colors.css :noweb yes :mkdirp yes :eval never /* Catppuccin Mocha Palette */ @define-color crust #11111b; @define-color mantle #181825; @define-color base #1e1e2e; @define-color base-alpha rgba(30, 30, 46, 0.9); @define-color surface0 #313244; @define-color surface1 #45475a; @define-color surface2 #585b70; @define-color overlay0 #6c7086; @define-color overlay1 #7f849c; @define-color overlay2 #9399b2; @define-color subtext0 #a6adc8; @define-color subtext1 #bac2de; @define-color text #cdd6f4; @define-color rosewater #f5e0dc; @define-color flamingo #f2cdcd; @define-color pink #f5c2e7; @define-color mauve #cba6f7; @define-color red #f38ba8; @define-color maroon #eba0ac; @define-color peach #fab387; @define-color yellow #f9e2af; @define-color green #a6e3a1; @define-color teal #94e2d5; @define-color sapphire #74c7ec; @define-color blue #89b4fa; @define-color lavender #b4befe; #+END_SRC ** =generated/.config/starship.toml= These are config files for Starship #+BEGIN_SRC toml :tangle generated/.config/starship.toml :noweb yes :mkdirp yes :eval never "$schema" = 'https://starship.rs/config-schema.json' format = """ [](red)\ $os\ $username\ [](bg:peach fg:red)\ $directory\ [](bg:yellow fg:peach)\ $git_branch\ $git_status\ [](fg:yellow bg:green)\ $c\ $rust\ $golang\ $nodejs\ $php\ $java\ $kotlin\ $haskell\ $python\ [](fg:green bg:sapphire)\ $conda\ [](fg:sapphire bg:lavender)\ $time\ [ ](fg:lavender)\ $cmd_duration\ $line_break\ $character""" palette = 'catppuccin_mocha' [os] disabled = false style = "bg:red fg:crust" [os.symbols] Windows = "" Ubuntu = "󰕈" SUSE = "" Raspbian = "󰐿" Mint = "󰣭" Macos = "󰀵" Manjaro = "" Linux = "󰌽" Gentoo = "󰣨" Fedora = "󰣛" Alpine = "" Amazon = "" Android = "" AOSC = "" Arch = "󰣇" Artix = "󰣇" CentOS = "" Debian = "󰣚" Redhat = "󱄛" RedHatEnterprise = "󱄛" [username] show_always = true style_user = "bg:red fg:crust" style_root = "bg:red fg:crust" format = '[ $user]($style)' [directory] style = "bg:peach fg:crust" format = "[ $path ]($style)" truncation_length = 3 truncation_symbol = "…/" [directory.substitutions] "Documents" = "󰈙 " "Downloads" = " " "Music" = "󰝚 " "Pictures" = " " "Developer" = "󰲋 " [git_branch] symbol = "" style = "bg:yellow" format = '[[ $symbol $branch ](fg:crust bg:yellow)]($style)' [git_status] style = "bg:yellow" format = '[[($all_status$ahead_behind )](fg:crust bg:yellow)]($style)' [nodejs] symbol = "" style = "bg:green" format = '[[ $symbol( $version) ](fg:crust bg:green)]($style)' [c] symbol = " " style = "bg:green" format = '[[ $symbol( $version) ](fg:crust bg:green)]($style)' [rust] symbol = "" style = "bg:green" format = '[[ $symbol( $version) ](fg:crust bg:green)]($style)' [golang] symbol = "" style = "bg:green" format = '[[ $symbol( $version) ](fg:crust bg:green)]($style)' [php] symbol = "" style = "bg:green" format = '[[ $symbol( $version) ](fg:crust bg:green)]($style)' [java] symbol = " " style = "bg:green" format = '[[ $symbol( $version) ](fg:crust bg:green)]($style)' [kotlin] symbol = "" style = "bg:green" format = '[[ $symbol( $version) ](fg:crust bg:green)]($style)' [haskell] symbol = "" style = "bg:green" format = '[[ $symbol( $version) ](fg:crust bg:green)]($style)' [python] symbol = "" style = "bg:green" format = '[[ $symbol( $version)(\(#$virtualenv\)) ](fg:crust bg:green)]($style)' [docker_context] symbol = "" style = "bg:sapphire" format = '[[ $symbol( $context) ](fg:crust bg:sapphire)]($style)' [conda] symbol = "  " style = "fg:crust bg:sapphire" format = '[$symbol$environment ]($style)' ignore_base = false [time] disabled = false time_format = "%R" style = "bg:lavender" format = '[[  $time ](fg:crust bg:lavender)]($style)' [line_break] disabled = false [character] disabled = false success_symbol = '[❯](bold fg:green)' error_symbol = '[❯](bold fg:red)' vimcmd_symbol = '[❮](bold fg:green)' vimcmd_replace_one_symbol = '[❮](bold fg:lavender)' vimcmd_replace_symbol = '[❮](bold fg:lavender)' vimcmd_visual_symbol = '[❮](bold fg:yellow)' [cmd_duration] show_milliseconds = true format = " in $duration " style = "bg:lavender" disabled = false show_notifications = true min_time_to_notify = 45000 [palettes.catppuccin_mocha] rosewater = "#f5e0dc" flamingo = "#f2cdcd" pink = "#f5c2e7" mauve = "#cba6f7" red = "#f38ba8" maroon = "#eba0ac" peach = "#fab387" yellow = "#f9e2af" green = "#a6e3a1" teal = "#94e2d5" sky = "#89dceb" sapphire = "#74c7ec" blue = "#89b4fa" lavender = "#b4befe" text = "#cdd6f4" subtext1 = "#bac2de" subtext0 = "#a6adc8" overlay2 = "#9399b2" overlay1 = "#7f849c" overlay0 = "#6c7086" surface2 = "#585b70" surface1 = "#45475a" surface0 = "#313244" base = "#1e1e2e" mantle = "#181825" crust = "#11111b" [palettes.catppuccin_frappe] rosewater = "#f2d5cf" flamingo = "#eebebe" pink = "#f4b8e4" mauve = "#ca9ee6" red = "#e78284" maroon = "#ea999c" peach = "#ef9f76" yellow = "#e5c890" green = "#a6d189" teal = "#81c8be" sky = "#99d1db" sapphire = "#85c1dc" blue = "#8caaee" lavender = "#babbf1" text = "#c6d0f5" subtext1 = "#b5bfe2" subtext0 = "#a5adce" overlay2 = "#949cbb" overlay1 = "#838ba7" overlay0 = "#737994" surface2 = "#626880" surface1 = "#51576d" surface0 = "#414559" base = "#303446" mantle = "#292c3c" crust = "#232634" [palettes.catppuccin_latte] rosewater = "#dc8a78" flamingo = "#dd7878" pink = "#ea76cb" mauve = "#8839ef" red = "#d20f39" maroon = "#e64553" peach = "#fe640b" yellow = "#df8e1d" green = "#40a02b" teal = "#179299" sky = "#04a5e5" sapphire = "#209fb5" blue = "#1e66f5" lavender = "#7287fd" text = "#4c4f69" subtext1 = "#5c5f77" subtext0 = "#6c6f85" overlay2 = "#7c7f93" overlay1 = "#8c8fa1" overlay0 = "#9ca0b0" surface2 = "#acb0be" surface1 = "#bcc0cc" surface0 = "#ccd0da" base = "#eff1f5" mantle = "#e6e9ef" crust = "#dce0e8" [palettes.catppuccin_macchiato] rosewater = "#f4dbd6" flamingo = "#f0c6c6" pink = "#f5bde6" mauve = "#c6a0f6" red = "#ed8796" maroon = "#ee99a0" peach = "#f5a97f" yellow = "#eed49f" green = "#a6da95" teal = "#8bd5ca" sky = "#91d7e3" sapphire = "#7dc4e4" blue = "#8aadf4" lavender = "#b7bdf8" text = "#cad3f5" subtext1 = "#b8c0e0" subtext0 = "#a5adcb" overlay2 = "#939ab7" overlay1 = "#8087a2" overlay0 = "#6e738d" surface2 = "#5b6078" surface1 = "#494d64" surface0 = "#363a4f" base = "#24273a" mantle = "#1e2030" crust = "#181926" #+END_SRC ** =generated/.config/stylix/stylix.conf= These are config files for .config/stylix #+BEGIN_SRC conf :tangle generated/.config/stylix/stylix.conf :noweb yes :mkdirp yes :eval never enable = true; base16Scheme = ../../../assets/system/theming/stylix/catppuccin-mocha.yaml; image = ../../../assets/hyprland/wallpaperstuff/pictures/wall1.jpg; polarity = "dark"; cursor = { package = "phinger-cursors"; # symbolic reference name = "phinger-cursors-light"; size = 24; }; fonts = { monospace = { package = "nerd-fonts-fira-code"; name = "Fira Code Nerd Font"; }; sansSerif = { package = "lato"; name = "Lato"; }; }; icons = { enable = true; package = "papirus-icon-theme"; dark = "Papirus-Dark"; light = "Papirus-Light"; }; #+END_SRC ** =generated/.config/stylix/palette.json= These are config files for .config/stylix #+BEGIN_SRC json :tangle generated/.config/stylix/palette.json :noweb yes :mkdirp yes :eval never { "base00": "1e1e2e", "base01": "181825", "base02": "313244", "base03": "45475a", "base04": "585b70", "base05": "cdd6f4", "base06": "f5e0dc", "base07": "b4befe", "base08": "f38ba8", "base09": "fab387", "base0A": "f9e2af", "base0B": "a6e3a1", "base0C": "94e2d5", "base0D": "89b4fa", "base0E": "cba6f7", "base0F": "f2cdcd", "author": "https://github.com/catppuccin/catppuccin", "scheme": "Catppuccin Mocha", "slug": "catppuccin-mocha" } #+END_SRC ** =generated/.config/stylix/palette.html= These are config files for .config/stylix #+BEGIN_SRC html :tangle generated/.config/stylix/palette.html :noweb yes :mkdirp yes :eval never

Primary colors

00
01
02
03
04
05
06
07

Accents

08
09
0A
0B
0C
0D
0E
0F

Documentation

Each color should be used as described in this table.

See the Stylix documentation for how to apply these colors on NixOS.

#+END_SRC ** =generated/.config/swaync/config.json= These are config files for waybar #+BEGIN_SRC json :tangle generated/.config/swaync/config.json :noweb yes :mkdirp yes :eval never { "positionX": "right", "positionY": "top", "layer": "overlay", "control-center-layer": "top", "layer-shell": true, "cssPriority": "application", "control-center-margin-top": 8, "control-center-margin-bottom": 8, "control-center-margin-right": 8, "control-center-margin-left": 0, "notification-2fa-action": true, "notification-inline-replies": false, "notification-icon-size": 48, "notification-body-image-height": 100, "notification-body-image-width": 200, "timeout": 10, "timeout-low": 5, "timeout-critical": 0, "fit-to-screen": false, "control-center-height": -1, "control-center-width": 300, "notification-window-width": 400, "keyboard-shortcuts": true, "image-visibility": "when-available", "transition-time": 200, "hide-on-clear": false, "hide-on-action": true, "script-fail-notify": true, "widgets": [ "inhibitors", "title", "dnd", "notifications" ], "widget-config": { "inhibitors": { "text": "Inhibitors", "button-text": "Clear All", "clear-all-button": true }, "title": { "text": "Notifications", "clear-all-button": true, "button-text": "Clear All" }, "dnd": { "text": "Do Not Disturb" }, "notifications": {} } } #+END_SRC ** =generated/.config/swaync/style.css= These are config files for waybar #+BEGIN_SRC css :tangle generated/.config/swaync/style.css :noweb yes :mkdirp yes :eval never @import url("/home/henrov/.config/shared/colors.css"); * { all: unset; font-size: 13px; font-family: sans-serif; transition: 200ms; } /* ── Notification rows ─────────────────────────────────────────────────── */ .notification-row { outline: none; margin: 4px 0; } .notification-row:focus, .notification-row:hover { opacity: 0.85; } /* ── Individual notification ───────────────────────────────────────────── */ .notification { border-radius: 12px; padding: 8px; margin: 4px 8px; color: @text; box-shadow: 0 2px 8px rgba(0, 0, 0, 0.4); /* gradient border */ border: 1px solid transparent; background-image: linear-gradient(@base-alpha, @base-alpha), linear-gradient(45deg, @blue, @green); background-clip: padding-box, border-box; background-origin: padding-box, border-box; } .notification-content { padding: 4px; } .notification-default-action { border-radius: 12px; } .notification-default-action:hover { background: alpha(@blue, 0.1); } /* ── Text elements ─────────────────────────────────────────────────────── */ .summary { font-size: 13px; font-weight: bold; color: @text; } .time { font-size: 11px; color: @overlay0; } .body { font-size: 12px; color: @subtext1; } /* ── Control center ────────────────────────────────────────────────────── */ .control-center { border-radius: 16px; padding: 8px; margin: 8px; color: @text; box-shadow: 0 4px 24px rgba(0, 0, 0, 0.5); /* gradient border */ border: 1px solid transparent; background-image: linear-gradient(@base, @base), /* ← was @mantle, @mantle */ linear-gradient(45deg, @blue, @green); background-clip: padding-box, border-box; background-origin: padding-box, border-box; } .control-center-list { background: transparent; } .control-center-list-placeholder { opacity: 0.4; font-size: 14px; } /* ── Misc windows ──────────────────────────────────────────────────────── */ .floating-notifications { background: transparent; } .blank-window { background: transparent; } /* ── Widget: title ─────────────────────────────────────────────────────── */ .widget-title { font-size: 14px; font-weight: bold; color: @blue; padding: 8px 4px 4px 4px; } .widget-title > button { font-size: 12px; color: @overlay0; background: alpha(@blue, 0.1); border-radius: 8px; padding: 2px 8px; } .widget-title > button:hover { background: alpha(@blue, 0.2); color: @text; } /* ── Widget: Do Not Disturb ────────────────────────────────────────────── */ .widget-dnd { padding: 4px; } .widget-dnd > switch { border-radius: 20px; background: alpha(@surface1, 0.3); /* gradient border */ border: 1px solid transparent; background-image: linear-gradient(alpha(@surface1, 0.3), alpha(@surface1, 0.3)), linear-gradient(45deg, @blue, @green); background-clip: padding-box, border-box; background-origin: padding-box, border-box; } .widget-dnd > switch:checked { background-image: linear-gradient(alpha(@blue, 0.5), alpha(@blue, 0.5)), linear-gradient(45deg, @blue, @green); background-clip: padding-box, border-box; background-origin: padding-box, border-box; } .widget-dnd > switch slider { border-radius: 20px; background: @text; min-width: 20px; min-height: 20px; } /* ── Widget: inhibitors ────────────────────────────────────────────────── */ .widget-inhibitors { padding: 4px; color: @red; font-size: 12px; } /* ── Close button ──────────────────────────────────────────────────────── */ .close-button { background: alpha(@red, 0.15); border-radius: 6px; color: @red; padding: 2px 6px; font-size: 11px; } .close-button:hover { background: alpha(@red, 0.3); } #+END_SRC ** =generated/.config/waybar/config.jsonc= These are config files for waybar #+BEGIN_SRC json :tangle generated/.config/waybar/config.jsonc :noweb yes :mkdirp yes :eval never { "layer": "top", "position": "top", "autohide": true, "autohide-blocked": false, "exclusive": true, "passthrough": false, "gtk-layer-shell": true, /*******************************************************************/ "modules-left": [ "group/connections" ,"group/hardware" ], "modules-center": [ "group/workspaces" ,"custom/power" ,"custom/media" ,"custom/batterywarn" /* ,"custom/kdeconnect" */ ], "modules-right": [ "group/audio" ,"tray" ,"clock" ,"idle_inhibitor" ,"custom/notifications" ], /*******************************************************************/ "group/workspaces": { "orientation": "horizontal", "modules": [ "hyprland/workspaces", "custom/windows" ] }, /*******************************************************************/ "group/hardware": { "orientation": "horizontal", "drawer": { "transition-duration": 500, "transition-left-to-right": true }, "modules": [ "custom/hardware-anchor", "battery", "cpu", "memory", "temperature" ] }, "custom/hardware-anchor": { "format": " ", "tooltip": false }, /*************************/ "group/connections": { "orientation": "horizontal", "drawer": { "transition-duration": 500, "transition-left-to-right": true }, "modules": [ "custom/connections-anchor", "custom/bluetooth", "network" ] }, "custom/connections-anchor": { "format": " ", "tooltip": false }, /*************************/ "group/audio": { "orientation": "horizontal", "modules": [ /* "custom/media", */ "pulseaudio", "pulseaudio/slider", ] }, /*******************************************************************/ "hyprland/workspaces": { "align": 1, "format": "{name}", "interval": 2, }, "custom/windows": { "align": 0, "format": "{text}", "exec": "~/.config/scripts/hypr-workspaces.sh", "interval": 2, "return-type": "json", "on-click": "~/.config/scripts/hypr-workspacesmenu.sh", "tooltip": true }, "custom/media": { "exec": "~/.config/scripts/media.sh", "interval": 1, "return-type": "json", "format": "{}", "on-click": "qs -c media", "max-length": 20, "scroll-step": 1, "tooltip": true }, "custom/bluetooth": { "exec": "~/.config/scripts/bluetooth-status.sh", "interval": 5, "return-type": "json", "on-click": "blueman-manager", "format": "{}" }, "custom/batterywarn": { "exec": "~/.config/scripts/batterywarn.sh", "interval": 60, "format": "{}" }, "custom/kdeconnect": { "format": "{name} {battery}% ", "interval": 10, "exec": "~/.config/scripts/kdeconnect-status.sh", "tooltip": true }, "custom/notifications": { "tooltip": false, "return-type": "json", "exec-if": "which swaync-client", "exec": "swaync-client -swb", "format": "{icon}", "format-icons": { "notification": "", "none": "", "dnd-notification": "󰂠", "dnd-none": "󰪓", }, "on-click": "swaync-client -t", "on-click-right": "swaync-client -d", "on-click-middle": "swaync-client -dn", }, "custom/power": { "format": "󰤄", "on-click": "qs -c powermenu", "tooltip-format": "Power Menu" }, "pulseaudio": { "format": "{volume}% {icon}", "format-bluetooth": "{volume}% {icon}", "format-muted": "", "format-icons": { "headphones": "", "headset": "", "phone": "", "portable": "", "default": ["", ""] }, "on-click": "pavucontrol" }, "pulseaudio/slider": { "min": 0, "max": 100, "orientation": "horizontal" }, "idle_inhibitor": { "tooltip": true, "format": "{icon}", "format-icons": { "activated": "  ", "deactivated": " 󰒲 " }, "tooltip-format-activated": "Staying awake", "tooltip-format-deactivated": "Might sleep...." }, "network": { "format-wifi": " ({bandwidthDownBits})", "format-ethernet": " ({bandwidthDownBits})", "format-disconnected": "Disconnected ⚠", "tooltip-format-wifi": "{essid} ({signalStrength}%)", "tooltip-format-ethernet": "{ifname}: {ipaddr}/{cidr}", "on-click": "networkmanager_dmenu --dmenu --style ~/.config/wofi/style.css --allow-images=false", "on-click-right": "nm-connection-editor" }, "cpu": { "format": "{usage}%  ", "tooltip": false }, "memory": { "format": "{percentage}%  " }, "temperature": { "format": "{temperatureC}°C ", "tooltip": false }, "tray": { "spacing": 10, "icon-size": 14 }, "battery": { "bat": "BAT0", "states": { "good": 95, "warning": 30, "critical": 15 }, "format": "{capacity}% {icon}", "format-charging": "{capacity}% 󰂄", "format-plugged": "{capacity}%  ", "format-icons": ["󰁺", "󰁼", "󰁾", "󰂀", "󱈏 "] } } #+END_SRC ** =generated/.config/waybar/style-dark.css= This file contains all css for waybar #+BEGIN_SRC css :tangle generated/.config/waybar/style-dark.css :noweb yes :mkdirp yes :eval never @import url("file:///home/henrov/.config/shared/colors.css"); /* --- Global --- */ * { font-family: Aporetic Sans Mono, Iosevka Nerd Font, Roboto, Helvetica, Arial, sans-serif; font-size: 13px; } window#waybar { background-color: transparent; color: @text; } /* --------------------------------------------------------- */ /* --- Group anchors default visible --- */ #custom-hardware-anchor, #custom-connections-anchor { min-width: 80px; padding: 0 5px; margin: 0 2px; opacity: 1; transition: opacity 0.2s ease, min-width 0.2s ease, padding 0.2s ease; } /* --- Hide anchors on hover of the group --- */ #hardware:hover #custom-hardware-anchor, #connections:hover #custom-connections-anchor { opacity: 0; min-width: 0; padding: 0; margin: 0; } #hardware:hover, #connections:hover { min-width: 80px; } /* MODULES */ .modules-left > widget, .modules-center > widget, .modules-right > widget { min-width: 80px; color: @text; font-weight: bold; border-radius: 30px; background: linear-gradient(@base-alpha, @base-alpha) padding-box, linear-gradient(45deg, @blue, @green) border-box; border: 2px solid transparent; } .modules-left > box + box, .modules-center > box + box, .modules-right > box + box { margin-left: 5px; } .modules-left > widget label, .modules-left > label , .modules-center > widget label, .modules-center > label, .modules-right > widget label, .modules-right > label { padding: 0px 5px; transition: padding 0.2s ease; } /* ----------------------------- WORKSPACES / WINDOWS MODULE ----------------------------- */ /* Disable hover effects completely */ #workspaces button, #workspaces button:hover { border: 2px solid transparent; padding: 0 6px; margin: 0; border-radius: 30px; transition: none; /* disable hover animation */ } /* Active vs inactive workspace colors */ #workspaces button.active { background: linear-gradient(45deg, @blue, @green); color: @base; } activeworkspaces:not(.active) { background: linear-gradient(@base-alpha, @base-alpha); border: 2px solid transparent; color: @text-muted; /* inactive text color */ } label#custom-windows.module { font-size: 14px; color: @base; padding: 0 8px; border-radius: 30px; transition: all 0.3s ease; } label#custom-windows.active { background: linear-gradient(45deg, alpha(@blue, 0.5), alpha(@green, 0.5)); } label#custom-windows:not(.active) { background: transparent; color: transparent; } /* ---- Media ---*/ #custom-media { padding: 0 8px; color: @text; } #custom-media.inactive { background: transparent; color: transparent; opacity: 0; padding: 0; margin: 0; min-width: 0; } /* ---- Pulseaudio ---*/ #pulseaudio-slider { padding: 0; margin: 0; } #pulseaudio-slider slider { min-height: 0px; min-width: 0px; opacity: 0; border-radius: 30px; background: linear-gradient(45deg, @blue, @green); border: none; box-shadow: none; } #pulseaudio-slider trough { min-height: 10px; min-width: 80px; border-radius: 30px; background: transparent; } #pulseaudio-slider highlight { min-width: 10px; border-radius: 30px; background: linear-gradient(45deg, @blue, @green); border: 2px solid transparent; } /* --------------------------------------------------------- */ /* STATES / SPECIALS */ #idle_inhibitor.activated { background: linear-gradient(45deg, @blue, @green); border: 2px solid transparent; color: @base; border-radius: 30px; } #battery.charging { color: @green; } #battery.warning:not(.charging) { color: white; animation: blink 0.5s linear infinite alternate; border-radius: 30px; border: 2px solid transparent; } #custom-battery-warn { margin: 0 5px; padding: 0 10px; color: white; animation: blink 0.5s linear infinite alternate; } @keyframes blink { to { background-color: #ffffff; color: black; border-radius: 30px; border: 2px solid transparent; } } #network.disconnected { background-color: @red; border-radius: 30px; border: 2px solid transparent; } #temperature.critical { background-color: @red; border-radius: 30px; border: 2px solid transparent; } /* --------------------------------------------------------- */ /* GLOBAL MODULE SPACING */ #clock, #idle_inhibitor, #battery:not(.warn), #cpu, #memory, #temperature, #network, #pulseaudio, #tray { margin: 0 5px; padding: 0 10px; } #+END_SRC ** =generated/.config/scripts/bluetooth-status.sh= These are config files for waybar #+BEGIN_SRC sh :tangle generated/.config/scripts/bluetooth-status.sh :shebang "#!/usr/bin/env bash" :noweb yes :mkdirp yes :eval never bt_connected="" while read -r _ mac name_rest; do if [ "$(bluetoothctl info "$mac" | awk '/Connected:/ {print $2}')" = "yes" ]; then bt_connected+="$name_rest\n" fi done < <(bluetoothctl devices) # icon if [ -n "$bt_connected" ]; then icon="" tooltip=$(printf "%b" "$bt_connected") else icon="" tooltip="No devices connected" fi # ALWAYS produce valid JSON printf '{"text": "%s", "tooltip": "%s"}\n' "$icon" "$tooltip" #+END_SRC ** =generated/.config/scripts/hypr-workspaces.sh= These are config files for waybar #+BEGIN_SRC sh :tangle generated/.config/scripts/hypr-workspaces.sh :shebang "#!/usr/bin/env bash" :noweb yes :mkdirp yes :eval never # Get focused monitor name focused_monitor=$(hyprctl monitors -j | jq -r '.[] | select(.focused==true) | .name') monitor="${WAYBAR_OUTPUT_NAME:-$focused_monitor}" # Hide if not focused monitor if [ "$monitor" != "$focused_monitor" ]; then jq -c -n '{text:"", class:"hidden"}' exit 0 fi # Get active workspace on this monitor active_ws=$(hyprctl monitors -j | jq -r \ ".[] | select(.name==\"$monitor\") | .activeWorkspace.id") # Get clients clients=$(hyprctl clients -j | jq -r \ ".[] | select(.workspace.id==$active_ws) | \"\(.title)\"") count=$(echo "$clients" | grep -c '\S') # Hide if 0 or 1 clients — no point showing window switcher if [ "$count" -le 1 ]; then jq -c -n '{text:"", class:"hidden"}' exit 0 fi tooltip=$(echo "$clients" | sed 's/^/• /' | paste -sd '\n' -) jq -c -n \ --arg text "$count" \ --arg tooltip "$tooltip" \ --arg class "active" \ '{text:$text, tooltip:$tooltip, class:$class}' #+END_SRC ** =generated/.config/scripts/hypr-workspacesmenu.sh= These are config files for waybar #+BEGIN_SRC sh :tangle generated/.config/scripts/hypr-workspacesmenu.sh :shebang "#!/usr/bin/env bash" :noweb yes :mkdirp yes :eval never active_ws=$(hyprctl activeworkspace -j | jq -r '.id') clients=$(hyprctl clients -j | jq -r \ ".[] | select(.workspace.id==$active_ws) | \"\(.address)|\(.title)\"") choice=$(echo "$clients" | cut -d'|' -f2 \ | wofi --dmenu \ --style ~/.config/wofi/style.css \ --allow-images=false \ --prompt "Active windows ...") [ -z "$choice" ] && exit 0 addr=$(echo "$clients" | grep "|$choice" | head -n1 | cut -d'|' -f1) hyprctl dispatch focuswindow address:"$addr" #+END_SRC ** =generated/.config/scripts/kdeconnect-status.sh= These are config files for waybar #+BEGIN_SRC sh :tangle generated/.config/scripts/kdeconnect-status.sh :shebang "#!/usr/bin/env bash" :noweb yes :mkdirp yes :eval never DEVICE=$(kdeconnect-cli --list-devices | grep -oP '(?<=\().*?(?=\))' | head -n 1) if [ -z "$DEVICE" ]; then echo "No phone" exit 0 fi NAME=$(kdeconnect-cli -d "$DEVICE" --name 2>/dev/null) BATTERY=$(kdeconnect-cli -d "$DEVICE" --battery 2>/dev/null | grep -o '[0-9]\+' | head -n 1) if [ -z "$BATTERY" ]; then echo "$NAME" else echo "$NAME $BATTERY%" fi #+END_SRC ** =generated/.config/waypaper/config.ini= These are config files for waypaper #+BEGIN_SRC conf :tangle generated/.config/waypaper/config.ini :noweb yes :mkdirp yes :eval never [Settings] language = en backend = awww folder = ~/Wallpapers/pictures monitors = All wallpaper = ~/Wallpapers/pictures/13.jpg show_path_in_tooltip = True fill = fill sort = name color = #ffffff subfolders = False all_subfolders = False show_hidden = False show_gifs_only = False zen_mode = False post_command = number_of_columns = 3 awww_transition_type = any awww_transition_step = 63 awww_transition_angle = 0 awww_transition_duration = 2 awww_transition_fps = 60 mpvpaper_sound = False mpvpaper_options = use_xdg_state = False stylesheet = /home/henrov/.config/waypaper/style.css keybindings = ~/.config/waypaper/keybindings.ini #+END_SRC ** =generated/.config/waypaper/config.ini= These are config files for .config/waypaper #+BEGIN_SRC ini :tangle generated/.config/waypaper/config.ini :noweb yes :mkdirp yes :eval never [Settings] language = en backend = awww folder = ~/Wallpapers/pictures monitors = All wallpaper = ~/Wallpapers/pictures/13.jpg show_path_in_tooltip = True fill = fill sort = name color = #ffffff subfolders = False all_subfolders = False show_hidden = False show_gifs_only = False zen_mode = False post_command = number_of_columns = 3 awww_transition_type = any awww_transition_step = 63 awww_transition_angle = 0 awww_transition_duration = 2 awww_transition_fps = 60 mpvpaper_sound = False mpvpaper_options = use_xdg_state = False stylesheet = /home/henrov/.config/waypaper/style.css keybindings = ~/.config/waypaper/keybindings.ini #+END_SRC ** =generated/.config/wofi/config= These are config files for .config/wofi #+BEGIN_SRC toml :tangle generated/.config/wofi/config :noweb yes :mkdirp yes :eval never [global] allow_markup = true location = center anchor = center lines = 10 columns = 1 sort_order = last-used sort_method = fuzzy allow_scrolling = true scroll_wrap = true scroll_step = 10 cycle = true hide_scroll = false hide_search = false prompt = > ... #+END_SRC ** =generated/.config/wofi/style.css= This is the default layout for wofi #+BEGIN_SRC css :tangle generated/.config/wofi/style.css :noweb yes :mkdirp yes :eval never @import "~/.config/shared/colors.css"; * { background-color: transparent; color: @text; font-family: "JetBrainsMono Nerd Font", monospace; font-size: 12pt; } #window { background: linear-gradient(45deg, #89b4fa, #a6e3a1); border-radius: 28px; padding: 2px; } #outer-box { background-color: rgba(30, 30, 46, 0.98); /* almost solid */ border-radius: 26px; padding: 12px; } #inner-box { background: transparent; padding: 0; } #input { background-color: @surface1; /* stronger than surface0 */ color: @text; border: 1px solid @surface2; border-radius: 18px; padding: 10px 14px; margin-bottom: 10px; } #input:focus { border: 1px solid @blue; background-color: @surface2; } #entry { background-color: rgba(0, 0, 0, 0.35); color: @subtext1; border-radius: 18px; padding: 10px 14px; margin: 2px 0; transition: all 0.15s ease; } #entry:hover { background-color: rgba(0, 0, 0, 0.5); color: @text; } #entry:focus { background: linear-gradient(45deg, #89b4fa, #89b4fa); color: @lavender; border-radius: 18px; } #entry:selected { background: linear-gradient(45deg, #89b4fa, #a6e3a1); border-radius: 18px; font-weight: bold; } #entry image { margin-right: 10px; opacity: 0.9; } #scrollbar { background-color: @surface1; border-radius: 20px; width: 6px; } #scrollbar handle { background: linear-gradient(45deg, #89b4fa, #a6e3a1); border-radius: 20px; } #prompt { color: @subtext0; margin-right: 6px; } #+END_SRC ** =generated/.config/zed/settings.json= These are config files for Zed editor #+BEGIN_SRC json :tangle generated/.config/zed/settings.json :noweb yes :mkdirp yes :eval never // Zed settings // // For information on how to configure Zed, see the Zed // documentation: https://zed.dev/docs/configuring-zed // // To see all of Zed's default settings without changing your // custom settings, run `zed: open default settings` from the // command palette (cmd-shift-p / ctrl-shift-p) { "icon_theme": "Catppuccin Mocha", "agent": { "default_model": { "provider": "ollama", "model": "codellama:34b", "enable_thinking": false }, "favorite_models": [], "model_parameters": [] }, "ui_font_size": 16, "buffer_font_size": 15, "theme": { "mode": "dark", "light": "One Light", "dark": "Catppuccin Mocha", }, } #+END_SRC ** =generated/.config/zsh/.zshrc= This sets up the zsh in the terminal #+BEGIN_SRC bash :tangle generated/.config/zsh/.zshrc :noweb yes :mkdirp yes :eval never # Path to syntax highlighting installed by Nix ZSH_SYNTAX_HIGHLIGHTING="${HOME}/.nix-profile/share/zsh-syntax-highlighting/zsh-syntax-highlighting.zsh" # Load syntax highlighting if available if [ -f "$ZSH_SYNTAX_HIGHLIGHTING" ]; then source "$ZSH_SYNTAX_HIGHLIGHTING" fi # Initialize Starship prompt if command -v starship >/dev/null 2>&1; then eval "$(starship init zsh)" fi source /etc/profile.d/99-alias-functions.sh eval "$(/run/current-system/sw/bin/z.lua --init zsh)" cd() { if [ "$#" -eq 0 ]; then builtin cd ~ else builtin cd "$@" || return fi command z "$PWD" } #+END_SRC