# Shared Waybar configuration with Stylix theming # Parameterized for use across multiple machines { config, pkgs, lib, ... }: let cfg = config.waybarConfig; in { options.waybarConfig = { enable = lib.mkEnableOption "Waybar with Stylix theming"; terminal = lib.mkOption { type = lib.types.str; default = "ghostty"; description = "Terminal emulator to use for on-click commands"; }; launcher = lib.mkOption { type = lib.types.str; default = "wofi --show=drun"; description = "Application launcher command"; }; fontSize = lib.mkOption { type = lib.types.int; default = 16; description = "Base font size for waybar"; }; font = lib.mkOption { type = lib.types.str; default = "Overpass Nerd Font"; description = "Font family for waybar"; }; position = lib.mkOption { type = lib.types.enum [ "top" "bottom" ]; default = "top"; description = "Bar position"; }; margin = lib.mkOption { type = lib.types.int; default = 3; description = "Margin around the bar in pixels"; }; extraModulesLeft = lib.mkOption { type = lib.types.listOf lib.types.str; default = []; description = "Additional modules to add to the left side"; }; extraModulesRight = lib.mkOption { type = lib.types.listOf lib.types.str; default = []; description = "Additional modules to add to the right side"; }; windowRewriteRules = lib.mkOption { type = lib.types.attrsOf lib.types.str; default = {}; description = "Additional window title rewrite rules"; }; workspaceIcons = lib.mkOption { type = lib.types.attrsOf lib.types.str; default = {}; description = "Additional workspace icons"; }; }; config = lib.mkIf cfg.enable { programs.waybar = { enable = true; settings = { mainBar = { layer = "top"; position = cfg.position; margin-top = cfg.margin; margin-left = cfg.margin; margin-right = cfg.margin; margin-bottom = cfg.margin; modules-left = [ "custom/launcher" "niri/workspaces" "niri/window" ] ++ cfg.extraModulesLeft; modules-right = cfg.extraModulesRight ++ [ "clock" "custom/storage" "memory" "cpu" "battery" "custom/wlsunset" "tray" "custom/power" ]; "idle_inhibitor" = { format = "{icon} "; format-icons = { activated = "󰛐"; deactivated = "󰛑"; }; }; battery = { states = { warning = 30; critical = 15; }; format = "{icon} {capacity}%"; format-charging = "{capacity}% 󰂄"; format-plugged = "{capacity}% "; format-icons = [ "󰁺" "󰁼" "󰁾" "󰂁" "󱈑" ]; }; clock = { interval = 1; format = "{:%I:%M.%S %p}"; tooltip-format = "{:%e %B %Y}"; }; cpu = { interval = 5; format = "  {usage}%"; states = { warning = 70; critical = 90; }; on-click = "${cfg.terminal} -e 'htop'"; }; memory = { interval = 5; format = " {}%"; on-click = "${cfg.terminal} -e 'htop'"; states = { warning = 70; critical = 90; }; }; network = { interval = 5; format-wifi = ""; format-ethernet = " {ifname}: {ipaddr}/{cidr}"; format-disconnected = "⚠ Disconnected"; tooltip-format = "{essid} - {ifname}:{ipaddr} {bandwidthUpBytes} {bandwidthDownBytes}"; on-click = "${cfg.terminal} -e 'nmtui'"; }; "niri/window" = { format = "{title}"; icon = true; icon-size = 20; rewrite = { # Firefox "(.*) — Mozilla Firefox" = " $1"; "(.*) - Mozilla Firefox" = " $1"; "Mozilla Firefox" = " Firefox"; # Chrome/Chromium "(.*) - Google Chrome" = " $1"; "(.*) - Chromium" = " $1"; "Google Chrome" = " Chrome"; "Chromium" = " Chromium"; # Terminals "(.*) - zsh" = " $1"; "(.*) - bash" = " $1"; "(.*) - fish" = " $1"; "ghostty" = " Terminal"; "kitty" = " Terminal"; "alacritty" = " Terminal"; # Editors/IDEs "(.*) - Visual Studio Code" = " $1"; "(.*) - Code" = " $1"; "(.*) - Vim" = " $1"; "(.*) - Neovim" = " $1"; "(.*) - Emacs" = " $1"; "Visual Studio Code" = " VS Code"; # File managers "(.*)Nautilus" = " Files: $1"; "Files" = " Files"; "Thunar" = " Files"; "Dolphin" = " Files"; # Communication "Slack (.*)" = " $1"; "Slack" = " Slack"; "Signal" = " Signal"; "Discord" = " Discord"; "Telegram" = " Telegram"; # Media "Spotify" = " Spotify"; "Steam" = " Steam"; "(.*) - YouTube" = "󰗃 $1"; "VLC media player" = "󰕼 VLC"; # Dev tools "(.*) - GitHub" = " $1"; "GitKraken" = " GitKraken"; "Postman" = " Postman"; # System "System Monitor" = " System Monitor"; "Task Manager" = " Task Manager"; "Settings" = " Settings"; "Control Panel" = " Settings"; # Office "(.*) - LibreOffice Writer" = " $1"; "(.*) - LibreOffice Calc" = " $1"; "(.*) - LibreOffice Impress" = " $1"; # Fallbacks "^(.*) - .*$" = "$1"; "^(.*) | .*$" = "$1"; "^$" = "Desktop"; } // cfg.windowRewriteRules; }; "niri/workspaces" = { disable-click = false; disable-markup = false; all-outputs = true; format = " {icon} "; format-icons = { term = ""; net = "󰖟"; chat = "󰭻"; scratch = ""; "1" = " 1"; "2" = " 2"; "3" = " 3"; "4" = " 4"; "5" = " 5"; "6" = " 6"; "7" = " 7"; "8" = " 8"; "9" = " 9"; } // cfg.workspaceIcons; }; pulseaudio = { scroll-step = 1; format = "{icon} {volume}%"; format-bluetooth = "{volume}% {icon} {format_source}"; format-bluetooth-muted = " {icon} {format_source}"; format-muted = " {format_source}"; format-source = "{volume}% "; format-source-muted = ""; format-icons = { # headphone = [ "" "" "" "" "" ]; # hands-free = ""; headset = ""; # phone = ""; # portable = ""; # car = ""; default = [ "" "" "" ]; }; on-click = "pavucontrol"; on-scroll-up = "pactl set-sink-volume @DEFAULT_SINK@ +2%"; on-scroll-down = "pactl set-sink-volume @DEFAULT_SINK@ -2%"; }; tray = { icon-size = 20; spacing = 10; }; backlight = { format = "{icon} {percent}%"; format-icons = [ "󰹐" "󱩏" "󱩑" "󱩓" "󱩕" "󰛨" ]; on-scroll-down = "brightnessctl -c backlight set 1%-"; on-scroll-up = "brightnessctl -c backlight set +1%"; min-brightness = 1; }; "custom/storage" = { format = "{icon} {percentage}%"; format-icons = { default = "󰋊"; warning = "󰋊"; critical = "󰋊"; }; exec = ''usage=$(df / --output=pcent | tail -n1 | tr -d ' %'); if [ $usage -ge 90 ]; then class="critical"; elif [ $usage -ge 75 ]; then class="warning"; else class="default"; fi; echo "{\"percentage\":$usage,\"class\":\"$class\"}"''; return-type = "json"; interval = 30; tooltip-format = "Root filesystem: {percentage}% used"; }; "custom/launcher" = { format = ""; on-click = cfg.launcher; tooltip = false; }; "custom/wlsunset" = { format = "{}"; exec = "if systemctl --user is-active --quiet wlsunset; then echo '󰖜'; else echo '󰖚'; fi"; on-click = "if systemctl --user is-active --quiet wlsunset; then systemctl --user stop wlsunset; else systemctl --user start wlsunset; fi; pkill -SIGRTMIN+8 waybar"; interval = "once"; signal = 8; tooltip = false; }; "custom/power" = { format = "⏻"; on-click = "entries='Logout Suspend Reboot Shutdown'; selected=$(printf '%s\\n' $entries | wofi --show=dmenu | awk '{print tolower($1)}'); case $selected in logout) niri msg action quit;; suspend) systemctl suspend;; reboot) systemctl reboot;; shutdown) systemctl poweroff -i;; esac"; tooltip = false; }; }; }; # Stylix provides @define-color variables for base16 colors style = '' /* Keyframes */ @keyframes blink-warning { 70% { color: @base05; } to { color: @base05; background-color: @base00; } } @keyframes blink-critical { 70% { color: @base05; } to { color: @base05; background-color: @base01; } } /* Reset all styles */ * { border: none; border-radius: 0; min-height: 30px; margin: 0px; padding: 0px; } /* The whole bar */ #waybar { background: transparent; background-color: transparent; font-family: ${cfg.font}; font-size: ${toString cfg.fontSize}px; color: @base05; } #taskbar { background: transparent; } #taskbar button { padding-left: 3px; padding-right: 3px; margin-left: 3px; margin-right: 3px; border-bottom: 2px solid; } #taskbar button.active { color: @base0B; } .modules-left, .modules-right { background: transparent; background-color: @base00; border-radius: 20px; padding: 0px 6px 0px 6px; border-style: solid; border-width: 3px; border-color: @base02; } .modules-center { background: transparent; border: none; padding: 0; min-height: 0; } #backlight, #battery, #clock, #cpu, #custom-storage, #custom-keyboard-layout, #custom-PBPbattery, #custom-weather, #idle_inhibitor, #memory, #mode, #network, #pulseaudio, #temperature, #tray { padding: 0.5rem 0.6rem; margin: 1px 0px; } #clock { margin-left: 5px; margin-right: 5px; min-width: 140px; } #backlight, #battery, #cpu, #custom-storage, #memory, #network, #pulseaudio, #temperature { min-width: 90px; } #battery { animation-timing-function: linear; animation-iteration-count: infinite; animation-direction: alternate; } #battery.warning, #custom-storage.warning { color: @base09; } #battery.critical, #custom-storage.critical { color: @base08; } #battery.warning.discharging { animation-name: blink-warning; animation-duration: 3s; } #battery.critical.discharging { animation-name: blink-critical; animation-duration: 2s; } #cpu.warning { color: @base09; } #cpu.critical { color: @base08; } #memory { animation-timing-function: linear; animation-iteration-count: infinite; animation-direction: alternate; } #memory.warning { color: @base09; } #memory.critical { color: @base08; animation-name: blink-critical; animation-duration: 2s; padding-left: 5px; padding-right: 5px; } #mode { background: @base03; border-bottom: 3px transparent; color: @base05; margin-left: 5px; margin-right: 5px; border-radius: 20px; } #network.disconnected { color: @base09; } #pulseaudio { padding-top: 6px; } #pulseaudio.muted { color: @base0C; } #temperature.critical { color: @base08; } #window { font-weight: bold; margin-left: 20px; margin-right: 10px; } #workspaces { font-size: ${toString cfg.fontSize}px; } #workspaces button { margin-bottom: 0px; padding: 0px; } #workspaces button.active { border-bottom: 3px solid @base0D; color: @base0B; } #workspaces button.urgent { border-color: @base0D; color: @base0A; } #custom-power { margin-left: 15px; margin-right: 15px; color: @base09; } #custom-launcher { margin-left: 15px; margin-right: 10px; } #backlight.icon { padding-right: 1px; } ''; }; }; }