From b74558e35bf2e60e20a6964d401231f4bbc522a6 Mon Sep 17 00:00:00 2001 From: Noa Aarts Date: Wed, 3 Apr 2024 21:25:04 +0200 Subject: [PATCH] modularize hyprland --- common/dunst.nix | 1 - modules/dunst.nix | 14 ++ modules/hyprland.nix | 44 +++-- modules/waybar.nix | 431 +++++++++++++++++++++++++++++++++++++++++++ modules/wofi.nix | 126 +++++++++++++ 5 files changed, 596 insertions(+), 20 deletions(-) create mode 100644 modules/dunst.nix create mode 100644 modules/waybar.nix create mode 100644 modules/wofi.nix diff --git a/common/dunst.nix b/common/dunst.nix index 818061d..05fe9fe 100644 --- a/common/dunst.nix +++ b/common/dunst.nix @@ -3,6 +3,5 @@ { services.dunst = { enable = true; - }; } diff --git a/modules/dunst.nix b/modules/dunst.nix new file mode 100644 index 0000000..052f450 --- /dev/null +++ b/modules/dunst.nix @@ -0,0 +1,14 @@ +{ config, lib, pkgs, inputs, ... }: +let + cfg = config.modules.dunst; +in +{ + options.modules.dunst = { + enable = lib.mkEnableOption "enable dunst for notifications"; + }; + config = lib.mkIf cfg.enable { + services.dunst = { + enable = true; + }; + }; +} diff --git a/modules/hyprland.nix b/modules/hyprland.nix index 310a8c9..0d18fe7 100644 --- a/modules/hyprland.nix +++ b/modules/hyprland.nix @@ -1,27 +1,34 @@ { config, lib, pkgs, inputs, ... }: let - hyprland = inputs.hyprland.packages.${pkgs.system}.hyprland; cfg = config.modules.hyprland; in { - options = { - cfg.enable = lib.mkEnableOption "enable hyprland"; - # TODO: make custom terminal support work better - # cfg.terminal = lib.mkOption { - # type = lib.types.package; - # default = pkgs.kitty; - # description = "What terminal emulator should be used in hyprland"; - # }; + options.modules.hyprland = { + enable = lib.mkEnableOption "enable hyprland"; + package = lib.mkOption { + type = lib.types.package; + default = pkgs.hyprland; + example = lib.literalExpression ''inputs.hyprland.packages.${pkgs.system}.hyprland''; + }; + terminal = lib.mkOption { + type = lib.types.package; + default = pkgs.kitty; + description = "What terminal emulator should be used in hyprland"; + }; }; + imports = [ + ./waybar.nix + ./wofi.nix + ./dunst.nix + ]; config = lib.mkIf cfg.enable { + modules = { + waybar.enable = lib.mkDefault true; + wofi.enable = lib.mkDefault true; + dunst.enable = lib.mkDefault true; + }; # these are necessary for the config to function correctly - imports = [ - ./kitty.nix - ./waybar.nix - ./wofi.nix - ./dunst.nix - ]; home.packages = with pkgs; [ # I always want these with hyprland anyways libnotify # to enable the notify-send command @@ -34,14 +41,13 @@ in playerctl ]; - programs.waybar.enable = true; - xdg.portal.configPackages = [ hyprland ]; + xdg.portal.configPackages = [ cfg.package ]; services.playerctld.enable = true; wayland.windowManager.hyprland = { enable = true; - package = hyprland; + package = cfg.package; settings = { monitor = [ "DP-3,2560x1440@360,2560x0,1" @@ -93,7 +99,7 @@ in }; "$mod" = "SUPER"; bind = [ - "$mod,Return,exec,${pkgs.kitty.pname}" + "$mod,Return,exec,${cfg.terminal.pname}" "$mod,tab,cyclenext" "SUPERSHIFT,Q,killactive" "$mod,SPACE,exec,wofi-launch" diff --git a/modules/waybar.nix b/modules/waybar.nix new file mode 100644 index 0000000..cb91d7c --- /dev/null +++ b/modules/waybar.nix @@ -0,0 +1,431 @@ +{ config, pkgs, lib, ... }: +let + cfg = config.modules.waybar; +in +{ + options.modules.waybar = { + enable = lib.mkEnableOption "enable waybar"; + package = lib.mkOption { + type = lib.types.package; + default = pkgs.waybar; + }; + }; + config = lib.mkIf cfg.enable { + home.packages = with pkgs; [ + font-awesome + ]; + programs.waybar = { + enable = true; + package = cfg.package; + settings = { + mainBar = { + layer = "top"; + position = "top"; + height = 39; + margin-top = 8; + margin-left = 10; + margin-right = 10; + output = [ + "DP-3" + "DP-2" + ]; + modules-left = [ "hyprland/workspaces" "tray" "custom/pronouns" "hyprland/window" ]; + modules-center = [ "clock" ]; + modules-right = [ "custom/vpn" "wireplumber" "battery" "network" "cpu" "memory" "temperature" "custom/poweroff" ]; + "clock" = { + tooltip-format = "{:%Y %B}\n\n{calendar}"; + interval = 1; + format = "{:%H:%M:%S}"; + format-alt = ":%Y-%m-%d %H:%M:%S}"; + on-click-middle = "gnome-clocks"; + calendar = { + weeks-pos = "left"; + format = { + today = "{}"; # TODO: use nix-colors + weeks = "{}"; # TODO: use nix-colors + }; + }; + }; + "tray".spacing = 10; + "cpu" = { + format = "cpu: {usage}%"; + tooltip = false; + }; + "memory" = { + format = "mem: {}%"; + tooltip = false; + }; + "wireplumber" = { + format = "{volume}% {icon}"; + format-muted = ""; + on-click = "helvum"; + format-icons = ["" "" ""]; + }; + "custom/vpn" = { + format = "VPN"; + exec = "echo '{\"class\": \"connected\"}'"; + exec-if = "test -d /proc/sys/net/ipv4/conf/tun0"; + return-type = "json"; + interval = 5; + }; + "temperature" = { + thermal-zone = 2; + hwmon-path = "/sys/class/hwmon/hwmon3/temp1_input"; + critical-threshold = 80; + format = "{temperatureC}°C {icon}"; + format-icons = ["" "" ""]; + }; + "custom/poweroff" = { + format = ""; + on-click = "wofi-power"; + on-click-right = "swaylock"; + }; + "battery" = { + bat = "hidpp_battery_2"; + states = { + full = 100; + good = 50; + warning = 30; + critical = 30; + }; + format = "mouse: {capacity}% {icon}"; + format-charging = "mouse: {capacity}% {icon}"; + format-plugged = "mouse: {capacity}% {icon}"; + format-alt = "mouse: {time} {icon}"; + interval = 1; + format-icons = [ + "󰂎" + "󰁻" + "󰁾" + "󰂀" + "󰁹" + ]; + }; + "hyprland/window" = { + max-length = 36; + }; + "network" = { + format-wifi = "{essid} ({signalStrength}%) 󰖩"; + format-ethernet = "{ipaddr}/{cidr} 󰛳"; + tooltip-format = "{ifname} via {gwaddr} 󰛳"; + format-linked = "{ifname} (No IP) 󰛳"; + format-disconnected = "Disconnected "; + format-alt = "{ifname}: {ipaddr}/{cidr}"; + }; + "custom/pronouns" = { + format = "{}"; + # exec = "${config.xdg.configHome}/waybar/pronouns"; # TODO: install pronouns + interval = 5; + }; + "hyprland/workspaces" = { + format = "{name}"; + on-click = "activate"; + sort-by = "id"; + }; + }; + }; + style = '' + * { + /* `otf-font-awesome` is required to be installed for icons */ + font-family: "Maple Mono NF"; + font-size: 14px; + } + + window#waybar { + background-color: transparent; + + border-radius: 999px; + color: #${config.colorScheme.palette.text}; + transition-property: background-color; + transition-duration: .5s; + } + window#waybar.hidden { + opacity: 0.2; + } + + window#waybar.termite { + background-color: transparent; + } + + window#waybar.chromium { + background-color: transparent; + } + + button { + /* Use box-shadow instead of border so the text isn't offset */ + box-shadow: inset 0 -1px transparent; + /* Avoid rounded borders under each button name */ + border: none; + border-radius: 0; + } + + /* https://githbackground: #000000ub.com/Alexays/Waybar/wiki/FAQ#the-workspace-buttons-have-a-strange-hover-effect */ + button:hover { + background: inherit; + border-radius: 999px; + } + + #workspaces button { + transition: all 0.2s; + padding: 3px 3px 3px 5px; + margin: 3px; + min-width: 15px; + min-height: 15px; + background-color: transparent; + color: #${config.colorScheme.palette.textMuted}; + border-radius: 999px; + } + + #workspaces button:hover { + background-color: #${config.colorScheme.palette.highlight}; + } + + #workspaces button.active { + color: #${config.colorScheme.palette.text}; + font-weight: bold; + background-color: #${config.colorScheme.palette.highlight}; + } + + #workspaces button.urgent { + background-color: #${config.colorScheme.palette.danger}; + } + + #clock, + #battery, + #cpu, + #memory, + #disk, + #temperature, + #backlight, + #network, + #pulseaudio, + #wireplumber, + #custom-media, + #mode, + #idle_inhibitor, + #custom-vpn, + #scratchpad, + #tray, + #custom-updates, + #custom-poweroff, + #mpd { + color: #${config.colorScheme.palette.textMuted}; + margin: 0px 2px; + padding: 0 15px; + + border-radius: 999px; + box-shadow: inset 0 0 0 1px #${config.colorScheme.palette.backgroundMuted}; + } + + .modules-right > widget:last-child > #battery { + margin-right: 0px; + } + + #tray { + padding: 4px 10px; + border-radius: 999px 999px 999px 999px; + box-shadow: inset 0px 0px 0 1px #${config.colorScheme.palette.backgroundMuted}; + } + + #window { + margin-left: 6px; + color: #${config.colorScheme.palette.textMuted}; + } + + #workspaces { + margin: 0 4px; + padding: 4px 4px; + border-radius: 999px; + box-shadow: inset 0px 0px 0 1px #${config.colorScheme.palette.backgroundMuted}; + } + + #cpu { + border-radius: 999px 0px 0px 999px; + margin-right: 0px; + } + + #memory { + border-radius: 0px; + padding: 0 10px; + margin: 0px; + box-shadow: inset 0px 2px 0 -1px #${config.colorScheme.palette.backgroundMuted}, + inset 0px -2px 0 -1px #${config.colorScheme.palette.backgroundMuted}; + } + + #clock { + box-shadow: none; + } + + + #battery { + min-width: 50px; + border-radius: 999px; + box-shadow: inset 0 0 0 1px #${config.colorScheme.palette.backgroundMuted}; + background-color: #${config.colorScheme.palette.backgroundMuted}; + transition: all 0.3s; + } + + #battery.charging, #battery.plugged { + color: #${config.colorScheme.palette.succes}; + background-color: transparent; + animation: batteryCharging 1.2s linear 0s infinite normal forwards, + } + #battery.full { + animation: batteryFull 7.0s linear 0s infinite normal forwards; + } + #battery.critical:not(.charging) { + background-color: #${config.colorScheme.palette.background}; + animation: batteryCritical 1.2s linear 0s infinite normal forwards; + } + + #network { + + } + + #network.disconnected, + #pulseaudio.muted { + transition: all 0.2s; + color: #${config.colorScheme.palette.backgroundMuted}; + } + + .custom-spotify { + color: #${config.colorScheme.palette.spotifyGreen}; + margin-right: 10px; + } + + #temperature { + margin-left: 0px; + border-radius: 0px 999px 999px 0px; + } + + #temperature.critical { + background-color: transparent; + color: #${config.colorScheme.palette.danger}; + } + + #tray { + background-color: transparent; + } + + + #tray > .passive { + -gtk-icon-effect: dim; + } + + #tray > .needs-attention { + background-color: #${config.colorScheme.palette.danger}; + border-radius: 999px; + } + + #scratchpad { + background: rgba(0, 0, 0, 0.1); + } + #scratchpad.empty { + background-color: transparent; + } + + #custom-updates { + box-shadow: inset 0 0 0 1px #${config.colorScheme.palette.backgroundMuted}; + color: #${config.colorScheme.palette.textMuted}; + transition: all 0.5s; + } + + #custom-updates.pending { + box-shadow: inset 0 0 0 2px #${config.colorScheme.palette.highlight}; + color: #${config.colorScheme.palette.highlight}; + font-weight: bold; + transition: all 0.5s; + } + + tooltip { + background-color: #${config.colorScheme.palette.background}; + border: 1px solid; + border-color: #${config.colorScheme.palette.border}; + border-radius: 10px; + color: #${config.colorScheme.palette.text}; + } + tooltip label { + padding: 5px; + } + + /* Keyframes ---------------------------------------------------------------- */ + + @keyframes batteryCritical { + 0% { + box-shadow: inset 0px 20px 8px -16px #${config.colorScheme.palette.danger}, + inset 0px -20px 8px -16px #${config.colorScheme.palette.danger}; + color: #${config.colorScheme.palette.danger}; + } + 50% { + box-shadow: inset 0px 12px 8px -16px #${config.colorScheme.palette.danger}, + inset 0px -12px 8px -16px #${config.colorScheme.palette.danger}; + color: #${config.colorScheme.palette.textMuted}; + } + 100% { + box-shadow: inset 0px 20px 8px -16px #${config.colorScheme.palette.danger}, + inset 0px -20px 8px -16px #${config.colorScheme.palette.danger}; + color: #${config.colorScheme.palette.danger}; + } + } + + @keyframes batteryCharging { + 0% { + box-shadow: inset 0px 0px 8px 0px #${config.colorScheme.palette.info}, + inset 0px 20px 8px -18px #${config.colorScheme.palette.ok}, + inset 0px -20px 8px -18px #${config.colorScheme.palette.ok}; + } + 25% { + box-shadow: inset 0px 0px 8px 0px #${config.colorScheme.palette.info}, + inset 14px 14px 8px -18px #${config.colorScheme.palette.ok}, + inset -14px -14px 8px -18px #${config.colorScheme.palette.ok}; + } + 50% { + box-shadow: inset 0px 0px 8px 0px #${config.colorScheme.palette.info}, + inset 20px 0px 8px -18px #${config.colorScheme.palette.ok}, + inset -20px 0px 8px -18px #${config.colorScheme.palette.ok}; + } + 75% { + box-shadow: inset 0px 0px 8px 0px #${config.colorScheme.palette.info}, + inset 14px -14px 8px -18px #${config.colorScheme.palette.ok}, + inset -14px 14px 8px -18px #${config.colorScheme.palette.ok}; + } + 100% { + box-shadow: inset 0px 0px 8px 0px #${config.colorScheme.palette.info}, + inset 0px -20px 8px -18px #${config.colorScheme.palette.ok}, + inset 0px 20px 8px -18px #${config.colorScheme.palette.ok}; + } + } + + + + @keyframes batteryFull { + 0% { + box-shadow: inset 0px 20px 8px -16px #${config.colorScheme.palette.warn}, + inset 0px -20px 8px -16px #${config.colorScheme.palette.warn}; + color: #${config.colorScheme.palette.warn}; + } + 25% { + box-shadow: inset 0px 19px 8px -16px #${config.colorScheme.palette.warn}, + inset 0px -19px 8px -16px #${config.colorScheme.palette.warn}; + color: #${config.colorScheme.palette.warn}; + } + 50% { + box-shadow: inset 0px 15px 8px -16px #${config.colorScheme.palette.warn}, + inset 0px -15px 8px -16px #${config.colorScheme.palette.warn}; + color: #${config.colorScheme.palette.warn}; + } + 75% { + box-shadow: inset 0px 19px 8px -16px #${config.colorScheme.palette.warn}, + inset 0px -19px 8px -16px #${config.colorScheme.palette.warn}; + color: #${config.colorScheme.palette.warn}; + } + 100% { + box-shadow: inset 0px 20px 8px -16px #${config.colorScheme.palette.warn}, + inset 0px -20px 8px -16px #${config.colorScheme.palette.warn}; + color: #${config.colorScheme.palette.warn}; + } + } + ''; + }; + }; +} diff --git a/modules/wofi.nix b/modules/wofi.nix new file mode 100644 index 0000000..41e9681 --- /dev/null +++ b/modules/wofi.nix @@ -0,0 +1,126 @@ +{ lib, config, pkgs, ... }: +let + cfg = config.modules.wofi; +in +{ + options.modules.wofi = { + enable = lib.mkEnableOption "enable wofi app launcher"; + }; + imports = [ + ../common/colors.nix + ]; + config = lib.mkIf cfg.enable { + home.packages = with pkgs; [ + (writeShellScriptBin "wofi-launch" '' + ${wofi}/bin/wofi --show drun + '') + (writeShellScriptBin "wofi-power" '' + lock="Lock" + poweroff="Poweroff" + reboot="Reboot" + sleep="Suspend" + + selected_option=$(echo -e "$lock\n$sleep\n$reboot\n$poweroff" | wofi --dmenu -i -p "Powermenu") + + if [ "$selected_option" == "$lock" ] + then + echo "lock" + swaylock + elif [ "$selected_option" == "$poweroff" ] + then + echo "poweroff" + poweroff + elif [ "$selected_option" == "$reboot" ] + then + echo "reboot" + reboot + elif [ "$selected_option" == "$sleep" ] + then + echo "sleep" + suspend + else + echo "No match" + fi + '') + ]; + programs.wofi = { + enable = true; + settings = { + + }; + style = '' + * { + outline: none; + outline-style: none; + } + + #window { + margin: 10px; + border: none; + background-color: #${config.colorScheme.palette.background}; + border-radius: 10px; + font-family: + JetBrains Mono NF, + monospace; + font-weight: bold; + font-size: 14px; + } + + #outer-box { + margin: 10px; + border: 2px #${config.colorScheme.palette.backgroundMuted}; + border-radius: 10px; + background-color: transparent; + } + + #input { + border: none; + border-radius: 10px; + margin-left: 2px; + color: #${config.colorScheme.palette.info}; + outline-style: none; + background-color: #${config.colorScheme.palette.background}; + } + + #scroll { + border: 10px solid #${config.colorScheme.palette.border}; + border-radius: 10px; + /*padding-right: 10px;*/ + outline: none; + background-color: #${config.colorScheme.palette.background}; + } + + #inner-box { + border: none; + border-radius: 10px; + background-color: transparent; + } + + #entry { + border: none; + /*border-radius: 10px; + margin-right: 15px; + margin-left: 15px;*/ + padding-right: 10px; + padding-left: 10px; + color: #${config.colorScheme.palette.text}; + background-color: #${config.colorScheme.palette.background}; + } + #entry:selected { + border: none; + background-color: #${config.colorScheme.palette.info}; + } + + #text:selected { + border: none; + color: #${config.colorScheme.palette.textMuted}; + } + + #img { + background-color: transparent; + margin-right: 6px; + } + ''; + }; + }; +}