inputs: { config, lib, pkgs, ... }: with lib; let cfg = config.colors; pow = n: i: if i == 1 then n else if i == 0 then 1 else n * pow n (i - 1); alf = [ "0" "1" "2" "3" "4" "5" "6" "7" "8" "9" "a" "b" "c" "d" "e" "f" ]; fil = c: lib.imap0 (n: x: if (lib.toLower x) == (lib.toLower c) then n else null) alf; fin = c: builtins.elemAt (builtins.filter (x: x != null) (fil c)) 0; add = l: lib.foldr ({ n, x }: c: (x * (pow 16 n)) + c) 0 (lib.imap0 (n: x: { inherit n x; }) l); calc = s: add (builtins.map fin (builtins.filter (x: builtins.isString x && builtins.stringLength x == 1) (builtins.split "" s))); splitHex = c: let s' = builtins.match "(..)(..)(..)|(.)(.)(.)" c; ss = builtins.elemAt s'; o = if ss 0 == null then 3 else 0; in { r = ss (0 + o); g = ss (1 + o); b = ss (2 + o); }; hexToRgb = c: builtins.mapAttrs (_: calc) (splitHex c); hexToAlphaCss = c: a: with hexToRgb c; "rgba(${r}, ${g}, ${b}, ${a})"; makeScheme = base16: lib.mapAttrs' (k: v: lib.nameValuePair "${k}-hex" v) base16 // lib.mapAttrs' (k: v: lib.nameValuePair "${k}-hex-r" (splitHex v).r) base16 // lib.mapAttrs' (k: v: lib.nameValuePair "${k}-hex-g" (splitHex v).g) base16 // lib.mapAttrs' (k: v: lib.nameValuePair "${k}-hex-b" (splitHex v).b) base16 // lib.mapAttrs' (k: v: lib.nameValuePair "${k}-rgb-r" (hexToRgb v).r) base16 // lib.mapAttrs' (k: v: lib.nameValuePair "${k}-rgb-g" (hexToRgb v).g) base16 // lib.mapAttrs' (k: v: lib.nameValuePair "${k}-rgb-b" (hexToRgb v).b) base16 // lib.mapAttrs' (k: v: lib.nameValuePair "${k}-dec-r" ((hexToRgb v).r / 255.0)) base16 // lib.mapAttrs' (k: v: lib.nameValuePair "${k}-dec-g" ((hexToRgb v).g / 255.0)) base16 // lib.mapAttrs' (k: v: lib.nameValuePair "${k}-dec-b" ((hexToRgb v).b / 255.0)) base16; mustache = scheme: src: pkgs.stdenv.mkDerivation ( { # TODO add template name name = "base16-generated"; inherit src; data = pkgs.writeText "base16-generated-data" (builtins.toJSON scheme); phases = [ "buildPhase" ]; buildPhase = "${pkgs.mustache-go}/bin/mustache $data $src > $out"; } ); scheme = (makeScheme cfg.base16 // { scheme-name = "base16 generated"; scheme-slug = "idk"; scheme-author = "nixos"; }); genTheme = repo: mustache scheme "${repo}/templates/default.mustache"; schemer2 = pkgs.buildGoPackage rec { pname = "schemer2"; version = "0.0.1"; goPackagePath = "github.com/thefryscorer/schemer2"; src = inputs.schemer2; vendorSha256 = "1fzlslz9xr3jay9kpvrg7sj1a0c1f1m1kn5rnis49hvlr1sc00d1"; meta = with lib; { description = "Terminal Colorscheme Generator and Converter"; homepage = "https://github.com/thefryscorer/schemer2"; }; }; in { options.colors = { enable = mkEnableOption "Enable automatic colors"; base16Rgb = mkOption { readOnly = true; type = types.attrsOf (types.attrsOf types.int); }; base16Split = mkOption { readOnly = true; type = types.attrsOf (types.attrsOf types.str); }; base16 = mkOption { readOnly = true; type = types.attrsOf types.str; }; baseColors = mkOption { type = types.either (types.attrsOf types.str) types.path; description = "base16 color scheme or path to an image to use to generate the scheme"; default = { # (monokai) base00 = "272822"; base01 = "383830"; base02 = "49483e"; base03 = "75715e"; base04 = "a59f85"; base05 = "f8f8f2"; base06 = "f5f4f1"; base07 = "f9f8f5"; base08 = "f92672"; base09 = "fd971f"; base0A = "f4bf75"; base0B = "a6e22e"; base0C = "a1efe4"; base0D = "66d9ef"; base0E = "ae81ff"; base0F = "cc6633"; }; }; }; config = let colorsJson = builtins.toFile "colors.json" (builtins.toJSON cfg.base16); themeHashOut = pkgs.runCommandNoCC "theme-hash" { } '' cat ${colorsJson} | ${pkgs.coreutils}/bin/sha256sum | ${pkgs.coreutils}/bin/head -c 8 > $out ''; themeHash = builtins.readFile themeHashOut; i3config = { config = { colors = { background = "#${cfg.base16.base07}"; focused = { border = "#${cfg.base16.base05}"; background = "#${cfg.base16.base0D}"; text = "#${cfg.base16.base00}"; indicator = "#${cfg.base16.base0D}"; childBorder = "#${cfg.base16.base0D}"; }; focusedInactive = { border = "#${cfg.base16.base01}"; background = "#${cfg.base16.base01}"; text = "#${cfg.base16.base05}"; indicator = "#${cfg.base16.base03}"; childBorder = "#${cfg.base16.base01}"; }; unfocused = { border = "#${cfg.base16.base01}"; background = "#${cfg.base16.base00}"; text = "#${cfg.base16.base05}"; indicator = "#${cfg.base16.base01}"; childBorder = "#${cfg.base16.base01}"; }; urgent = { border = "#${cfg.base16.base08}"; background = "#${cfg.base16.base08}"; text = "#${cfg.base16.base00}"; indicator = "#${cfg.base16.base08}"; childBorder = "#${cfg.base16.base08}"; }; placeholder = { border = "#${cfg.base16.base00}"; background = "#${cfg.base16.base00}"; text = "#${cfg.base16.base05}"; indicator = "#${cfg.base16.base00}"; childBorder = "#${cfg.base16.base00}"; }; }; }; }; elementTheme = { name = "colors-${themeHash}"; is_dark = true; colors = { # "accent-color" = "#${cfg.base16.base02}"; # "primary-color" = "#${cfg.base16.base08}"; # "warning-color" = "#${cfg.base16.base0F}"; # "sidebar-color" = "#${cfg.base16.base01}"; # "roomlist-background-color" = "#${cfg.base16.base00}"; # "roomlist-text-color" = "#${cfg.base16.base05}"; # "roomlist-text-secondary-color" = "${cfg.base16.base06}"; # "roomlist-highlights-color" = "#${cfg.base16.base02}"; # "roomlist-separator-color" = "#${cfg.base16.base05}"; # "timeline-background-color" = "#${cfg.base16.base00}"; # "timeline-text-color" = "#${cfg.base16.base07}"; # "timeline-text-secondary-color" = "#${cfg.base16.base05}"; # "timeline-highlights-color" = "#${cfg.base16.base02}"; # "reaction-row-button-selected-bg-color" = "#${cfg.base16.base0B}"; "accent-color" = "#${cfg.base16.base02}"; "accent" = "#${cfg.base16.base02}"; "primary-color" = "#${cfg.base16.base0B}"; "warning-color" = "#${cfg.base16.base08}"; "alert" = "#${cfg.base16.base08}"; "sidebar-color" = "#${cfg.base16.base00}"; "roomlist-background-color" = "#${cfg.base16.base01}"; "roomlist-text-color" = "#${cfg.base16.base05}"; "roomlist-text-secondary-color" = "${cfg.base16.base09}"; "roomlist-highlights-color" = "#${cfg.base16.base08}"; "roomlist-separator-color" = "#${cfg.base16.base05}"; "timeline-background-color" = "#${cfg.base16.base00}"; "timeline-text-color" = "#${cfg.base16.base05}"; "secondary-content" = "#${cfg.base16.base05}"; "tertiary-content" = "#${cfg.base16.base05}"; "timeline-text-secondary-color" = "#${cfg.base16.base06}"; "timeline-highlights-color" = "#${cfg.base16.base03}"; "reaction-row-button-selected-bg-color" = "#${cfg.base16.base04}"; "menu-selected-color" = "#${cfg.base16.base04}"; "focus-bg-color" = "#${cfg.base16.base04}"; "room-highlight-color" = "#${cfg.base16.base04}"; "other-user-pill-bg-color" = "#${cfg.base16.base04}"; "togglesw-off-color" = "#${cfg.base16.base04}"; "username-colors" = [ "#${cfg.base16.base08}" "#${cfg.base16.base09}" "#${cfg.base16.base0A}" "#${cfg.base16.base0B}" "#${cfg.base16.base0C}" "#${cfg.base16.base0D}" "#${cfg.base16.base0E}" "#${cfg.base16.base0F}" ]; # "avatar-background-colors" = [ "#${cfg.base16.base03}" "#${cfg.base16.base04}" "#${cfg.base16.base05}" ]; }; }; elementConfig = { settingDefaults.custom_themes = [ elementTheme ]; settingDefaults.theme = "${elementTheme.name}"; default_theme = "${elementTheme.name}"; showLabsSettings = true; show_labs_settings = true; }; base16FromImageSrc = pkgs.runCommandNoCC "auto-image-base16" { } '' ${schemer2}/bin/schemer2 -format img::colors -in ${cfg.baseColors} -out colors.txt && ${pkgs.python3}/bin/python3 ${inputs.auto-base16-theme}/AutoBase16Theme.py ${inputs.auto-base16-theme}/templates/base16-template.yaml auto-image-base16.yaml ${pkgs.yaml2json}/bin/yaml2json < auto-image-base16.yaml > $out ''; base16FromImage = lib.filterAttrs (k: v: k != "scheme" && k != "author") (builtins.fromJSON (builtins.readFile base16FromImageSrc)); in mkIf cfg.enable { # Read only utility attributes colors.base16 = if builtins.typeOf cfg.baseColors == "set" then cfg.baseColors else base16FromImage; colors.base16Rgb = builtins.mapAttrs hexToRgb cfg.base16; colors.base16Split = builtins.mapAttrs splitHex cfg.base16; # Element xdg.configFile."Riot/config.json".text = builtins.toJSON elementConfig; xdg.configFile."Element/config.json".text = builtins.toJSON elementConfig; # And in case you want to do something with the generated theme yourself xdg.configFile."Riot/theme.json".text = builtins.toJSON elementTheme; xdg.configFile."Element/theme.json".text = builtins.toJSON elementTheme; # Mako programs.mako = { backgroundColor = "#${cfg.base16.base00}"; textColor = "#${cfg.base16.base07}"; borderColor = "#${cfg.base16.base08}"; progressColor = "over #${cfg.base16.base0D}"; }; # I3/sway wayland.windowManager.sway = i3config; xsession.windowManager.i3 = i3config; # Dunst services.dunst = { settings = { global = { frame_color = "#${cfg.base16.base09}"; separator_color = "#${cfg.base16.base05}"; }; urgency_low = { background = "#${cfg.base16.base01}"; foreground = "#${cfg.base16.base03}"; }; urgency_normal = { background = "#${cfg.base16.base02}"; foreground = "#${cfg.base16.base05}"; }; urgency_critical = { background = "#${cfg.base16.base08}"; foreground = "#${cfg.base16.base06}"; }; }; }; # Rofi programs.rofi.theme = "${genTheme inputs.base16-rofi}"; # Kitty programs.kitty.extraConfig = '' include ${genTheme inputs.base16-kitty} ''; # Kermit programs.kermit.extraConfig = builtins.readFile (genTheme inputs.base16-kermit); # neovim xdg.configFile."nvim/colors/base16.vim".source = "${genTheme inputs.base16-vim}"; programs.neovim.extraConfig = '' colorscheme base16 set termguicolors ''; # GTK gtk = { enable = true; theme = let generated-gtk-theme = pkgs.callPackage "${inputs.rycee}/pkgs/materia-theme" { configBase16 = { name = "Generated"; kind = "dark"; colors = builtins.mapAttrs (k: v: { hex.rgb = v; }) cfg.base16; }; }; in { name = "Generated"; package = generated-gtk-theme; }; }; xdg.configFile."geary/user-style.css".text = '' :root, *:not(a) { background-color: #${cfg.base16.base00} !important; color: #${cfg.base16.base05} !important; } ''; systemd.user.sessionVariables.GTK_THEME = "Generated"; home.sessionVariables.GTK_THEME = "Generated"; # Codium/VSCODE programs.vscode.userSettings = { "workbench.colorTheme" = "nix colors"; }; home.file = lib.mkMerge [ ( mkIf config.programs.vscode.enable { ".vscode-oss/extensions/base16-1.0.0/themes/nix-colors.json".source = genTheme inputs.base16-vscode; ".vscode-oss/extensions/base16-1.0.0/package.json".text = builtins.toJSON { name = "nix colors"; displayName = "Automatic Nix-generated base16 colors"; version = "1.0.0"; publisher = "colors"; author = { name = "ezpc usr"; email = "usr@ezpc"; }; engines.vscode = "^1.11.1"; categories = "Themes"; contributes.themes = [ { label = "nix colors"; uiTheme = "vs-dark"; path = "./themes/nix-colors.json"; } ]; }; } ) ]; }; }