diff --git a/modules/tuigreet/meta.nix b/modules/tuigreet/meta.nix new file mode 100644 index 000000000..4208dba85 --- /dev/null +++ b/modules/tuigreet/meta.nix @@ -0,0 +1,11 @@ +{ + name = "TUIgreet"; + homepage = "https://github.com/apognu/tuigreet"; + maintainers = []; + description = '' + Applies Stylix colors to TUIgreet by generating an ANSI theme string at + /etc/tuigreet/stylix.theme. Ensure greetd invokes TUIgreet with a + `--theme` argument, for example: + `--theme "$(cat /etc/tuigreet/stylix.theme)"`. + ''; +} diff --git a/modules/tuigreet/nixos.nix b/modules/tuigreet/nixos.nix new file mode 100644 index 000000000..ee0095854 --- /dev/null +++ b/modules/tuigreet/nixos.nix @@ -0,0 +1,39 @@ +{ + mkTarget, + pkgs, + config, + lib, + ... +}: +mkTarget { + name = "tuigreet"; + humanName = "TUIgreet"; + + # Auto-enable only when greetd is enabled and configured to run TUIgreet + autoEnable = + pkgs.stdenv.hostPlatform.isLinux + && (config.services.greetd.enable or false) + && lib.hasInfix "tuigreet" + (config.services.greetd.settings.default_session.command or ""); + autoEnableExpr = '' + pkgs.stdenv.hostPlatform.isLinux && (config.services.greetd.enable or false) + && lib.hasInfix "tuigreet" (config.services.greetd.settings.default_session.command or "") + ''; + + # Generate a complete ANSI --theme string and nudge users to wire it in + configElements = [ + ( + {}: let themeString = config.lib.stylix.ansi.themeStringNearest; in {environment.etc."tuigreet/stylix.theme".text = themeString + "\n";} + ) + { + # Nudge users to wire the config into greetd if they are using tuigreet + warnings = let + cmd = config.services.greetd.settings.default_session.command or ""; + usesTuigreet = lib.hasInfix "tuigreet" cmd; + hasTheme = lib.hasInfix "--theme" cmd; + needsConfig = usesTuigreet && !hasTheme; + in + lib.optional needsConfig "stylix: tuigreet: services.greetd.settings.default_session.command does not include a '--theme' argument"; + } + ]; +} diff --git a/stylix/ansi.nix b/stylix/ansi.nix new file mode 100644 index 000000000..9652c0009 --- /dev/null +++ b/stylix/ansi.nix @@ -0,0 +1,170 @@ +{ + lib, + config, + ... +}: { + # ANSI helpers (nearest-color mapping) and scheme-sensitive theme string + config.lib.stylix.ansi = let + # Default component mapping (Base16 -> semantic UI elements) + defaultComponents = { + text = "base05"; + time = "base0C"; + container = "base00"; + border = "base03"; + title = "base0E"; + greet = "base0C"; + prompt = "base0B"; + input = "base0D"; + action = "base0D"; + button = "base0A"; + }; + + # Scheme-sensitive nearest ANSI mapping + # Reference RGB for ANSI names (0..255) + ansiRGB = { + black = { + r = 0; + g = 0; + b = 0; + }; + red = { + r = 205; + g = 0; + b = 0; + }; + green = { + r = 0; + g = 205; + b = 0; + }; + yellow = { + r = 205; + g = 205; + b = 0; + }; + blue = { + r = 0; + g = 0; + b = 205; + }; + magenta = { + r = 205; + g = 0; + b = 205; + }; + cyan = { + r = 0; + g = 205; + b = 205; + }; + white = { + r = 229; + g = 229; + b = 229; + }; + + # Bright variants (standard 16-color set) + "bright-black" = { + r = 102; + g = 102; + b = 102; + }; + "bright-red" = { + r = 255; + g = 0; + b = 0; + }; + "bright-green" = { + r = 0; + g = 255; + b = 0; + }; + "bright-yellow" = { + r = 255; + g = 255; + b = 0; + }; + "bright-blue" = { + r = 0; + g = 0; + b = 255; + }; + "bright-magenta" = { + r = 255; + g = 0; + b = 255; + }; + "bright-cyan" = { + r = 0; + g = 255; + b = 255; + }; + "bright-white" = { + r = 255; + g = 255; + b = 255; + }; + }; + + # Access Base16 RGB components from the current scheme and convert to ints + getRgb = name: comp: lib.toInt (config.lib.stylix.colors."${name}-rgb-${comp}"); + rgbOfBase = name: { + r = getRgb name "r"; + g = getRgb name "g"; + b = getRgb name "b"; + }; + dist2 = a: b: let + dr = a.r - b.r; + dg = a.g - b.g; + db = a.b - b.b; + in + dr * dr + dg * dg + db * db; + nearestNameFor = baseName: let + c = rgbOfBase baseName; + keys = builtins.attrNames ansiRGB; + scored = + map (k: { + name = k; + d = dist2 c ansiRGB.${k}; + }) + keys; + sorted = lib.sort (a: b: a.d < b.d) scored; + in + (builtins.head sorted).name; + + # Build a theme map and string using nearest ANSI for each component's Base16 + themeMapNearest = let + comps = defaultComponents; + in { + text = nearestNameFor comps.text; + time = nearestNameFor comps.time; + container = nearestNameFor comps.container; + border = nearestNameFor comps.border; + title = nearestNameFor comps.title; + greet = nearestNameFor comps.greet; + prompt = nearestNameFor comps.prompt; + input = nearestNameFor comps.input; + action = nearestNameFor comps.action; + button = nearestNameFor comps.button; + }; + + themeStringNearest = + lib.concatStringsSep ";" + (map ( + k: "${k}=" + (builtins.getAttr k themeMapNearest) + ) [ + "text" + "time" + "container" + "border" + "title" + "greet" + "prompt" + "input" + "action" + "button" + ]); + in { + inherit defaultComponents themeMapNearest themeStringNearest; + }; +} diff --git a/stylix/hm/default.nix b/stylix/hm/default.nix index 832dd5162..68079e094 100644 --- a/stylix/hm/default.nix +++ b/stylix/hm/default.nix @@ -8,6 +8,7 @@ let in { imports = [ + ../ansi.nix ./cursor.nix ./icons.nix ./palette.nix diff --git a/stylix/nixos/default.nix b/stylix/nixos/default.nix index 71e36ecbc..5b298011f 100644 --- a/stylix/nixos/default.nix +++ b/stylix/nixos/default.nix @@ -8,6 +8,7 @@ let in { imports = [ + ../ansi.nix ./cursor.nix ./palette.nix ../cursor.nix