# Waybar — two-tier theming: # # 1. Default: structure, fonts, geometry AND palette baked from # theme-state.json (colors as GTK named colors, @define-color). # # 2. Whole-swap: themes with their own visual identity ship # //waybar.css (and optionally waybar.jsonc) which # replace the generated style/layout entirely. Probed at eval time — # pure, it's flake source. { config, lib, ... }: let t = config.nomarchy.theme; # Per-theme override probe. assetDir = config.nomarchy.themesDir + "/${t.slug}"; styleOverride = assetDir + "/waybar.css"; configOverride = assetDir + "/waybar.jsonc"; hasStyleOverride = builtins.pathExists styleOverride; hasConfigOverride = builtins.pathExists configOverride; # The palette as GTK named colors, straight from the JSON. colorDefs = lib.concatStringsSep "\n" (lib.mapAttrsToList (name: value: "@define-color ${name} ${value};") t.colors); generatedSettings = { layer = "top"; position = "top"; height = 34; margin-top = t.ui.gapsOut; margin-left = t.ui.gapsOut; margin-right = t.ui.gapsOut; spacing = 8; # waybar re-reads style.css when it changes on disk, so a # home-manager switch restyles the running bar without a restart. reload_style_on_change = true; modules-left = [ "hyprland/workspaces" "hyprland/window" ]; modules-center = [ "clock" ]; modules-right = [ "tray" "pulseaudio" "network" "cpu" "memory" "battery" ]; "hyprland/workspaces" = { format = "{icon}"; on-click = "activate"; }; "hyprland/window" = { max-length = 48; separate-outputs = true; }; clock = { format = "{:%H:%M}"; format-alt = "{:%A %d %B %Y}"; tooltip-format = "{calendar}"; }; pulseaudio = { format = "{icon} {volume}%"; format-muted = "󰝟"; format-icons.default = [ "󰕿" "󰖀" "󰕾" ]; on-click = "pamixer -t"; }; network = { format-wifi = "󰤨 {essid}"; format-ethernet = "󰈀"; format-disconnected = "󰤭"; tooltip-format = "{ipaddr} via {gwaddr}"; }; cpu.format = "󰍛 {usage}%"; memory.format = "󰾆 {percentage}%"; battery = { states = { warning = 25; critical = 10; }; format = "{icon} {capacity}%"; format-charging = "󰂄 {capacity}%"; format-icons = [ "󰁺" "󰁼" "󰁾" "󰂀" "󰁹" ]; }; tray.spacing = 8; }; generatedStyle = '' /* Palette baked from theme-state.json */ ${colorDefs} * { font-family: "${t.fonts.ui}", "${t.fonts.mono}"; font-size: ${toString t.fonts.size}pt; min-height: 0; } window#waybar { background: alpha(@base, 0.85); color: @text; border: ${toString t.ui.borderSize}px solid alpha(@accent, 0.4); border-radius: ${toString t.ui.rounding}px; } #workspaces button { padding: 0 8px; color: @muted; border-radius: ${toString t.ui.rounding}px; } #workspaces button.active { color: @base; background: @accent; } #workspaces button.urgent { color: @base; background: @bad; } #window { color: @subtext; padding: 0 12px; } #clock { color: @text; font-weight: bold; } #tray, #pulseaudio, #network, #cpu, #memory, #battery { color: @subtext; padding: 0 10px; } #pulseaudio.muted { color: @muted; } #battery.warning { color: @warn; } #battery.critical { color: @bad; } #battery.charging { color: @good; } ''; in { programs.waybar = lib.mkIf config.nomarchy.waybar.enable { enable = true; systemd.enable = true; # started/stopped with graphical-session.target settings.mainBar = if hasConfigOverride then builtins.fromJSON (builtins.readFile configOverride) else generatedSettings; style = if hasStyleOverride then builtins.readFile styleOverride else generatedStyle; }; }