self: { config, lib, pkgs, ... }: let cfg = config.programs.nova-shell; stylixAvailable = config ? lib && config.lib ? stylix; stylixTheme = let c = config.lib.stylix.colors.withHashtag; f = config.stylix.fonts; in { colors = { inherit (c) base00 base01 base02 base03 base04 base05 base06 base07 base08 base09 base0A base0B base0C base0D base0E base0F ; }; fontFamily = f.sansSerif.name; fontSize = f.sizes.desktop; barOpacity = 1.0 - config.stylix.opacity.desktop; iconFontFamily = "Symbols Nerd Font"; }; in { options.programs.nova-shell = { enable = lib.mkEnableOption "nova-shell Quickshell bar"; package = lib.mkOption { type = lib.types.package; default = self.packages.${pkgs.stdenv.hostPlatform.system}.default; description = "nova-shell package to use."; }; modules = let moduleOpt = name: extra: lib.mkOption { default = { }; description = "Configuration for the ${name} module."; type = lib.types.submodule { options = { enable = lib.mkOption { type = lib.types.bool; default = true; description = "Enable the ${name} module."; }; } // extra; }; }; intervalOpt = default: { interval = lib.mkOption { type = lib.types.int; inherit default; description = "Polling interval in milliseconds."; }; }; simpleModules = lib.genAttrs [ "workspaces" "tray" "windowTitle" "clock" "notifications" "mpris" "volume" "idleInhibitor" "power" ] (name: moduleOpt name { }); in simpleModules // { bluetooth = moduleOpt "bluetooth" (intervalOpt 5000); network = moduleOpt "network" (intervalOpt 5000); powerProfile = moduleOpt "powerProfile" (intervalOpt 5000); cpu = moduleOpt "cpu" (intervalOpt 1000); memory = moduleOpt "memory" (intervalOpt 2000); disk = moduleOpt "disk" (intervalOpt 30000); backlight = moduleOpt "backlight" { step = lib.mkOption { type = lib.types.int; default = 5; description = "Brightness adjustment step (%)."; }; }; temperature = moduleOpt "temperature" ( (intervalOpt 2000) // { warm = lib.mkOption { type = lib.types.int; default = 60; description = "Temperature threshold for warm state (°C)."; }; hot = lib.mkOption { type = lib.types.int; default = 80; description = "Temperature threshold for hot state (°C)."; }; } ); battery = moduleOpt "battery" { warning = lib.mkOption { type = lib.types.int; default = 25; description = "Battery percentage for warning notification."; }; critical = lib.mkOption { type = lib.types.int; default = 15; description = "Battery percentage for critical notification and blink."; }; }; weather = moduleOpt "weather" ( (intervalOpt 3600000) // { args = lib.mkOption { type = lib.types.listOf lib.types.str; default = [ "--nerd" ]; description = "Arguments passed to wttrbar."; example = [ "--nerd" "--location" "Berlin" ]; }; } ); }; theme = lib.mkOption { type = lib.types.attrsOf lib.types.anything; default = { }; description = '' Theme overrides written to `$XDG_CONFIG_HOME/nova-shell/theme.json`. Keys: colors (base00-base0F), fontFamily, iconFontFamily, fontSize, barOpacity, barHeight, barPadding, barSpacing, moduleSpacing, radius. Automatically populated from stylix when it is available. ''; }; systemd = { enable = lib.mkOption { type = lib.types.bool; default = true; description = "Run nova-shell as a systemd user service."; }; target = lib.mkOption { type = lib.types.str; default = "graphical-session.target"; description = "Systemd target to bind the service to."; }; }; }; config = lib.mkIf cfg.enable { home.packages = [ self.packages.${pkgs.stdenv.hostPlatform.system}.nova-shell-cli pkgs.nerd-fonts.symbols-only ] ++ lib.optional cfg.modules.weather.enable pkgs.wttrbar ++ lib.optional cfg.modules.mpris.enable pkgs.cava; xdg.configFile."nova-shell/modules.json".source = (pkgs.formats.json { }).generate "nova-shell-modules.json" cfg.modules; xdg.configFile."nova-shell/theme.json".source = let stylixDefaults = if stylixAvailable then stylixTheme else { }; finalTheme = lib.recursiveUpdate stylixDefaults cfg.theme; in (pkgs.formats.json { }).generate "nova-shell-theme.json" finalTheme; systemd.user.services.nova-shell = lib.mkIf cfg.systemd.enable { Unit = { Description = "nova-shell Quickshell bar"; PartOf = [ cfg.systemd.target ]; After = [ cfg.systemd.target ]; }; Service = { ExecStart = lib.getExe cfg.package; Restart = "on-failure"; Slice = "session.slice"; }; Install.WantedBy = [ cfg.systemd.target ]; }; }; }