/nixos.nix" ];
+```
diff --git a/flake.lock b/flake.lock
new file mode 100644
index 0000000..7486ec2
--- /dev/null
+++ b/flake.lock
@@ -0,0 +1,309 @@
+{
+ "nodes": {
+ "base16": {
+ "inputs": {
+ "fromYaml": "fromYaml"
+ },
+ "locked": {
+ "lastModified": 1732200724,
+ "narHash": "sha256-+R1BH5wHhfnycySb7Sy5KbYEaTJZWm1h+LW1OtyhiTs=",
+ "owner": "SenchoPens",
+ "repo": "base16.nix",
+ "rev": "153d52373b0fb2d343592871009a286ec8837aec",
+ "type": "github"
+ },
+ "original": {
+ "owner": "SenchoPens",
+ "repo": "base16.nix",
+ "type": "github"
+ }
+ },
+ "base16-fish": {
+ "flake": false,
+ "locked": {
+ "lastModified": 1622559957,
+ "narHash": "sha256-PebymhVYbL8trDVVXxCvZgc0S5VxI7I1Hv4RMSquTpA=",
+ "owner": "tomyun",
+ "repo": "base16-fish",
+ "rev": "2f6dd973a9075dabccd26f1cded09508180bf5fe",
+ "type": "github"
+ },
+ "original": {
+ "owner": "tomyun",
+ "repo": "base16-fish",
+ "type": "github"
+ }
+ },
+ "base16-helix": {
+ "flake": false,
+ "locked": {
+ "lastModified": 1725860795,
+ "narHash": "sha256-Z2o8VBPW3I+KKTSfe25kskz0EUj7MpUh8u355Z1nVsU=",
+ "owner": "tinted-theming",
+ "repo": "base16-helix",
+ "rev": "7f795bf75d38e0eea9fed287264067ca187b88a9",
+ "type": "github"
+ },
+ "original": {
+ "owner": "tinted-theming",
+ "repo": "base16-helix",
+ "type": "github"
+ }
+ },
+ "base16-vim": {
+ "flake": false,
+ "locked": {
+ "lastModified": 1731949548,
+ "narHash": "sha256-XIDexXM66sSh5j/x70e054BnUsviibUShW7XhbDGhYo=",
+ "owner": "tinted-theming",
+ "repo": "base16-vim",
+ "rev": "61165b1632409bd55e530f3dbdd4477f011cadc6",
+ "type": "github"
+ },
+ "original": {
+ "owner": "tinted-theming",
+ "repo": "base16-vim",
+ "type": "github"
+ }
+ },
+ "flake-compat": {
+ "flake": false,
+ "locked": {
+ "lastModified": 1696426674,
+ "narHash": "sha256-kvjfFW7WAETZlt09AgDn1MrtKzP7t90Vf7vypd3OL1U=",
+ "owner": "edolstra",
+ "repo": "flake-compat",
+ "rev": "0f9255e01c2351cc7d116c072cb317785dd33b33",
+ "type": "github"
+ },
+ "original": {
+ "owner": "edolstra",
+ "repo": "flake-compat",
+ "type": "github"
+ }
+ },
+ "flake-utils": {
+ "inputs": {
+ "systems": [
+ "systems"
+ ]
+ },
+ "locked": {
+ "lastModified": 1731533236,
+ "narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=",
+ "owner": "numtide",
+ "repo": "flake-utils",
+ "rev": "11707dc2f618dd54ca8739b309ec4fc024de578b",
+ "type": "github"
+ },
+ "original": {
+ "owner": "numtide",
+ "repo": "flake-utils",
+ "type": "github"
+ }
+ },
+ "fromYaml": {
+ "flake": false,
+ "locked": {
+ "lastModified": 1731966426,
+ "narHash": "sha256-lq95WydhbUTWig/JpqiB7oViTcHFP8Lv41IGtayokA8=",
+ "owner": "SenchoPens",
+ "repo": "fromYaml",
+ "rev": "106af9e2f715e2d828df706c386a685698f3223b",
+ "type": "github"
+ },
+ "original": {
+ "owner": "SenchoPens",
+ "repo": "fromYaml",
+ "type": "github"
+ }
+ },
+ "git-hooks": {
+ "inputs": {
+ "flake-compat": [
+ "flake-compat"
+ ],
+ "gitignore": "gitignore",
+ "nixpkgs": [
+ "nixpkgs"
+ ],
+ "nixpkgs-stable": [
+ "git-hooks",
+ "nixpkgs"
+ ]
+ },
+ "locked": {
+ "lastModified": 1731363552,
+ "narHash": "sha256-vFta1uHnD29VUY4HJOO/D6p6rxyObnf+InnSMT4jlMU=",
+ "owner": "cachix",
+ "repo": "git-hooks.nix",
+ "rev": "cd1af27aa85026ac759d5d3fccf650abe7e1bbf0",
+ "type": "github"
+ },
+ "original": {
+ "owner": "cachix",
+ "repo": "git-hooks.nix",
+ "type": "github"
+ }
+ },
+ "gitignore": {
+ "inputs": {
+ "nixpkgs": [
+ "git-hooks",
+ "nixpkgs"
+ ]
+ },
+ "locked": {
+ "lastModified": 1709087332,
+ "narHash": "sha256-HG2cCnktfHsKV0s4XW83gU3F57gaTljL9KNSuG6bnQs=",
+ "owner": "hercules-ci",
+ "repo": "gitignore.nix",
+ "rev": "637db329424fd7e46cf4185293b9cc8c88c95394",
+ "type": "github"
+ },
+ "original": {
+ "owner": "hercules-ci",
+ "repo": "gitignore.nix",
+ "type": "github"
+ }
+ },
+ "gnome-shell": {
+ "flake": false,
+ "locked": {
+ "lastModified": 1732369855,
+ "narHash": "sha256-JhUWbcYPjHO3Xs3x9/Z9RuqXbcp5yhPluGjwsdE2GMg=",
+ "owner": "GNOME",
+ "repo": "gnome-shell",
+ "rev": "dadd58f630eeea41d645ee225a63f719390829dc",
+ "type": "github"
+ },
+ "original": {
+ "owner": "GNOME",
+ "ref": "47.2",
+ "repo": "gnome-shell",
+ "type": "github"
+ }
+ },
+ "home-manager": {
+ "inputs": {
+ "nixpkgs": [
+ "nixpkgs"
+ ]
+ },
+ "locked": {
+ "lastModified": 1735774425,
+ "narHash": "sha256-C73gLFnEh8ZI0uDijUgCDWCd21T6I6tsaWgIBHcfAXg=",
+ "owner": "nix-community",
+ "repo": "home-manager",
+ "rev": "5f6aa268e419d053c3d5025da740e390b12ac936",
+ "type": "github"
+ },
+ "original": {
+ "owner": "nix-community",
+ "repo": "home-manager",
+ "type": "github"
+ }
+ },
+ "nixpkgs": {
+ "locked": {
+ "lastModified": 1735648875,
+ "narHash": "sha256-fQ4k/hyQiH9RRPznztsA9kbcDajvwV1sRm01el6Sr3c=",
+ "owner": "NixOS",
+ "repo": "nixpkgs",
+ "rev": "47e29c20abef74c45322eca25ca1550cdf5c3b50",
+ "type": "github"
+ },
+ "original": {
+ "owner": "NixOS",
+ "ref": "nixos-unstable",
+ "repo": "nixpkgs",
+ "type": "github"
+ }
+ },
+ "root": {
+ "inputs": {
+ "base16": "base16",
+ "base16-fish": "base16-fish",
+ "base16-helix": "base16-helix",
+ "base16-vim": "base16-vim",
+ "flake-compat": "flake-compat",
+ "flake-utils": "flake-utils",
+ "git-hooks": "git-hooks",
+ "gnome-shell": "gnome-shell",
+ "home-manager": "home-manager",
+ "nixpkgs": "nixpkgs",
+ "systems": "systems",
+ "tinted-foot": "tinted-foot",
+ "tinted-kitty": "tinted-kitty",
+ "tinted-tmux": "tinted-tmux"
+ }
+ },
+ "systems": {
+ "locked": {
+ "lastModified": 1681028828,
+ "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
+ "owner": "nix-systems",
+ "repo": "default",
+ "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
+ "type": "github"
+ },
+ "original": {
+ "owner": "nix-systems",
+ "repo": "default",
+ "type": "github"
+ }
+ },
+ "tinted-foot": {
+ "flake": false,
+ "locked": {
+ "lastModified": 1726913040,
+ "narHash": "sha256-+eDZPkw7efMNUf3/Pv0EmsidqdwNJ1TaOum6k7lngDQ=",
+ "owner": "tinted-theming",
+ "repo": "tinted-foot",
+ "rev": "fd1b924b6c45c3e4465e8a849e67ea82933fcbe4",
+ "type": "github"
+ },
+ "original": {
+ "owner": "tinted-theming",
+ "repo": "tinted-foot",
+ "rev": "fd1b924b6c45c3e4465e8a849e67ea82933fcbe4",
+ "type": "github"
+ }
+ },
+ "tinted-kitty": {
+ "flake": false,
+ "locked": {
+ "lastModified": 1716423189,
+ "narHash": "sha256-2xF3sH7UIwegn+2gKzMpFi3pk5DlIlM18+vj17Uf82U=",
+ "owner": "tinted-theming",
+ "repo": "tinted-kitty",
+ "rev": "eb39e141db14baef052893285df9f266df041ff8",
+ "type": "github"
+ },
+ "original": {
+ "owner": "tinted-theming",
+ "repo": "tinted-kitty",
+ "rev": "eb39e141db14baef052893285df9f266df041ff8",
+ "type": "github"
+ }
+ },
+ "tinted-tmux": {
+ "flake": false,
+ "locked": {
+ "lastModified": 1729501581,
+ "narHash": "sha256-1ohEFMC23elnl39kxWnjzH1l2DFWWx4DhFNNYDTYt54=",
+ "owner": "tinted-theming",
+ "repo": "tinted-tmux",
+ "rev": "f0e7f7974a6441033eb0a172a0342e96722b4f14",
+ "type": "github"
+ },
+ "original": {
+ "owner": "tinted-theming",
+ "repo": "tinted-tmux",
+ "type": "github"
+ }
+ }
+ },
+ "root": "root",
+ "version": 7
+}
diff --git a/flake.nix b/flake.nix
index ce5906f..379adc7 100644
--- a/flake.nix
+++ b/flake.nix
@@ -1,5 +1,219 @@
{
- outputs = inputs: {
- nixosModules.stylix = import ./default.nix;
+ inputs = {
+ base16-fish = {
+ flake = false;
+ url = "github:tomyun/base16-fish";
+ };
+
+ base16-helix = {
+ flake = false;
+ url = "github:tinted-theming/base16-helix";
+ };
+
+ base16-vim = {
+ flake = false;
+ url = "github:tinted-theming/base16-vim";
+ };
+
+ base16.url = "github:SenchoPens/base16.nix";
+
+ flake-compat = {
+ flake = false;
+ url = "github:edolstra/flake-compat";
+ };
+
+ flake-utils = {
+ inputs.systems.follows = "systems";
+ url = "github:numtide/flake-utils";
+ };
+
+ git-hooks = {
+ inputs = {
+ flake-compat.follows = "flake-compat";
+ nixpkgs-stable.follows = "git-hooks/nixpkgs";
+ nixpkgs.follows = "nixpkgs";
+ };
+
+ url = "github:cachix/git-hooks.nix";
+ };
+
+ gnome-shell = {
+ flake = false;
+
+ # TODO: Unlocking the input and pointing to official repository requires
+ # updating the patch:
+ # https://github.com/danth/stylix/pull/224#discussion_r1460339607.
+ url = "github:GNOME/gnome-shell/47.2";
+ };
+
+ # The 'home-manager' input is used to generate the documentation.
+ home-manager = {
+ inputs.nixpkgs.follows = "nixpkgs";
+ url = "github:nix-community/home-manager";
+ };
+
+ nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
+
+ # Interface flake systems.
+ systems.url = "github:nix-systems/default";
+
+ tinted-foot = {
+ flake = false;
+
+ # Lock the tinted-foot input to prevent upstream breaking changes.
+ #
+ # Considering that Stylix eventually re-implements this input's
+ # functionality [1], it might be easiest to lock this input to avoid
+ # wasted maintenance effort.
+ #
+ # [1]: https://github.com/danth/stylix/issues/571
+ url = "github:tinted-theming/tinted-foot/fd1b924b6c45c3e4465e8a849e67ea82933fcbe4";
+ };
+
+ tinted-tmux = {
+ flake = false;
+ url = "github:tinted-theming/tinted-tmux";
+ };
+
+ tinted-kitty = {
+ flake = false;
+
+ # Lock the tinted-kitty input to prevent upstream breaking changes.
+ #
+ # Considering that Stylix eventually re-implements this input's
+ # functionality [1], it might be easiest to lock this input to avoid
+ # wasted maintenance effort.
+ #
+ # [1]: https://github.com/danth/stylix/issues/534
+ url = "github:tinted-theming/tinted-kitty/eb39e141db14baef052893285df9f266df041ff8";
+ };
};
+
+ outputs =
+ {
+ nixpkgs,
+ base16,
+ self,
+ ...
+ }@inputs:
+ inputs.flake-utils.lib.eachDefaultSystem (
+ system:
+ let
+ inherit (nixpkgs) lib;
+ pkgs = nixpkgs.legacyPackages.${system};
+ in
+ {
+ checks = lib.attrsets.unionOfDisjoint {
+ git-hooks = inputs.git-hooks.lib.${system}.run {
+ hooks = {
+ deadnix.enable = true;
+ hlint.enable = true;
+
+ nixfmt-rfc-style = {
+ enable = true;
+ settings.width = 80;
+ };
+
+ statix.enable = true;
+ stylish-haskell.enable = true;
+ typos.enable = true;
+ yamllint.enable = true;
+ };
+
+ src = ./.;
+ };
+ } self.packages.${system};
+
+ devShells = {
+ default = pkgs.mkShell {
+ inherit (self.checks.${system}.git-hooks) shellHook;
+
+ packages = [
+ inputs.home-manager.packages.${system}.default
+ self.checks.${system}.git-hooks.enabledPackages
+ ];
+ };
+
+ ghc = pkgs.mkShell {
+ inputsFrom = [ self.devShells.${system}.default ];
+ packages = [ pkgs.ghc ];
+ };
+ };
+
+ packages =
+ let
+ universalPackages = {
+ docs = import ./docs { inherit pkgs inputs lib; };
+
+ nix-flake-check = pkgs.writeShellApplication {
+ meta.description = "A parallelized alternative to 'nix flake check'";
+ name = "nix-flake-check";
+
+ runtimeInputs = with pkgs; [
+ nix
+ parallel
+ ];
+
+ text = ''
+ nix flake show --json --no-update-lock-file |
+ jq --raw-output '
+ ((.checks."${system}" // {}) | keys) as $checks |
+ ((.packages."${system}" // {}) | keys) as $packages |
+ (($checks - $packages)[] | "checks.${system}.\(.)"),
+ ($packages[] | "packages.${system}.\(.)")
+ ' |
+ parallel --halt now,fail=1 '
+ nix build --no-update-lock-file --verbose .#{}
+ '
+ '';
+ };
+
+ palette-generator = pkgs.callPackage ./palette-generator { };
+ };
+
+ # Testbeds are virtual machines based on NixOS, therefore they are
+ # only available for Linux systems.
+ testbedPackages = lib.optionalAttrs (lib.hasSuffix "-linux" system) (
+ import ./stylix/testbed.nix { inherit pkgs inputs lib; }
+ );
+ in
+ universalPackages // testbedPackages;
+ }
+ )
+ // {
+ nixosModules.stylix =
+ { pkgs, ... }@args:
+ {
+ imports = [
+ (import ./stylix/nixos inputs {
+ inherit (self.packages.${pkgs.system}) palette-generator;
+ base16 = base16.lib args;
+ homeManagerModule = self.homeManagerModules.stylix;
+ })
+ ];
+ };
+
+ homeManagerModules.stylix =
+ { pkgs, ... }@args:
+ {
+ imports = [
+ (import ./stylix/hm inputs {
+ inherit (self.packages.${pkgs.system}) palette-generator;
+ base16 = base16.lib args;
+ })
+ ];
+ };
+
+ darwinModules.stylix =
+ { pkgs, ... }@args:
+ {
+ imports = [
+ (import ./stylix/darwin inputs {
+ inherit (self.packages.${pkgs.system}) palette-generator;
+ base16 = base16.lib args;
+ homeManagerModule = self.homeManagerModules.stylix;
+ })
+ ];
+ };
+ };
}
diff --git a/gnome.png b/gnome.png
new file mode 100644
index 0000000..7702581
Binary files /dev/null and b/gnome.png differ
diff --git a/kde.png b/kde.png
new file mode 100644
index 0000000..9acd4b7
Binary files /dev/null and b/kde.png differ
diff --git a/modules/alacritty/hm.nix b/modules/alacritty/hm.nix
new file mode 100644
index 0000000..cdf9506
--- /dev/null
+++ b/modules/alacritty/hm.nix
@@ -0,0 +1,64 @@
+# Documentation is available at:
+# - https://alacritty.org/config-alacritty.html
+# - `man 5 alacritty`
+{ config, lib, ... }:
+
+let
+ colors = config.lib.stylix.colors.withHashtag;
+in
+{
+ options.stylix.targets.alacritty.enable =
+ config.lib.stylix.mkEnableTarget "Alacritty" true;
+
+ config =
+ lib.mkIf (config.stylix.enable && config.stylix.targets.alacritty.enable)
+ {
+ programs.alacritty.settings = {
+ font = with config.stylix.fonts; {
+ normal = {
+ family = monospace.name;
+ style = "Regular";
+ };
+ size = sizes.terminal;
+ };
+ window.opacity = with config.stylix.opacity; terminal;
+ colors = with colors; {
+ primary = {
+ foreground = base05;
+ background = base00;
+ bright_foreground = base07;
+ };
+ selection = {
+ text = base05;
+ background = base02;
+ };
+ cursor = {
+ text = base00;
+ cursor = base05;
+ };
+ normal = {
+ black = base00;
+ white = base05;
+ inherit
+ red
+ green
+ yellow
+ blue
+ magenta
+ cyan
+ ;
+ };
+ bright = {
+ black = base03;
+ white = base07;
+ red = bright-red;
+ green = bright-green;
+ inherit yellow;
+ blue = bright-blue;
+ magenta = bright-magenta;
+ cyan = bright-cyan;
+ };
+ };
+ };
+ };
+}
diff --git a/modules/alacritty/testbed.nix b/modules/alacritty/testbed.nix
new file mode 100644
index 0000000..602273f
--- /dev/null
+++ b/modules/alacritty/testbed.nix
@@ -0,0 +1,22 @@
+{ pkgs, ... }:
+
+let
+ package = pkgs.alacritty;
+
+in
+{
+ stylix.testbed.application = {
+ enable = true;
+ name = "Alacritty";
+ inherit package;
+ };
+
+ home-manager.sharedModules = [
+ {
+ programs.alacritty = {
+ enable = true;
+ inherit package;
+ };
+ }
+ ];
+}
diff --git a/modules/avizo/hm.nix b/modules/avizo/hm.nix
new file mode 100644
index 0000000..7ad1517
--- /dev/null
+++ b/modules/avizo/hm.nix
@@ -0,0 +1,33 @@
+{
+ config,
+ lib,
+ options,
+ ...
+}:
+
+with config.lib.stylix.colors;
+with config.stylix.fonts;
+let
+ aviOpacity = toString config.stylix.opacity.popups;
+in
+{
+ options.stylix.targets.avizo.enable =
+ config.lib.stylix.mkEnableTarget "Avizo" true;
+
+ # Referenced https://github.com/stacyharper/base16-mako
+ config = lib.optionalAttrs (options.services ? avizo) (
+ lib.mkIf (config.stylix.enable && config.stylix.targets.avizo.enable) {
+ services.avizo = {
+ settings = {
+ default = {
+ background = "rgba(${base01-rgb-r}, ${base01-rgb-g}, ${base01-rgb-b}, ${aviOpacity})";
+ border-color = "rgba(${base0D-rgb-r}, ${base0D-rgb-g}, ${base0D-rgb-b}, ${aviOpacity})";
+ bar-fg-color = "rgba(${base05-rgb-r}, ${base05-rgb-g}, ${base05-rgb-b}, ${aviOpacity})";
+ bar-bg-color = "rgba(${base01-rgb-r}, ${base01-rgb-g}, ${base01-rgb-b}, ${aviOpacity})";
+ image-opacity = aviOpacity;
+ };
+ };
+ };
+ }
+ );
+}
diff --git a/modules/bat/base16-stylix.mustache b/modules/bat/base16-stylix.mustache
new file mode 100644
index 0000000..1359154
--- /dev/null
+++ b/modules/bat/base16-stylix.mustache
@@ -0,0 +1,538 @@
+
+
+
+
+ author
+ Template: Chris Kempson, Scheme: Mitchell Kember
+ name
+ Base16 Stylix
+ colorSpaceName
+ sRGB
+ settings
+
+
+ settings
+
+ background
+ #{{base00-hex}}
+ caret
+ #{{base05-hex}}
+ foreground
+ #{{base05-hex}}
+ invisibles
+ #{{base03-hex}}
+ lineHighlight
+ #{{base03-hex}}
+ selection
+ #{{base02-hex}}
+ gutter
+ #{{base01-hex}}
+ gutterForeground
+ #{{base03-hex}}
+
+
+
+ name
+ Text
+ scope
+ variable.parameter.function
+ settings
+
+ foreground
+ #{{base05-hex}}
+
+
+
+ name
+ Comments
+ scope
+ comment, punctuation.definition.comment
+ settings
+
+ foreground
+ #{{base03-hex}}
+
+
+
+ name
+ Punctuation
+ scope
+ punctuation.definition.string, punctuation.definition.variable, punctuation.definition.string, punctuation.definition.parameters, punctuation.definition.string, punctuation.definition.array
+ settings
+
+ foreground
+ #{{base05-hex}}
+
+
+
+ name
+ Delimiters
+ scope
+ none
+ settings
+
+ foreground
+ #{{base05-hex}}
+
+
+
+ name
+ Operators
+ scope
+ keyword.operator
+ settings
+
+ foreground
+ #{{base05-hex}}
+
+
+
+ name
+ Keywords
+ scope
+ keyword
+ settings
+
+ foreground
+ #{{base0E-hex}}
+
+
+
+ name
+ Variables
+ scope
+ variable
+ settings
+
+ foreground
+ #{{base05-hex}}
+
+
+
+ name
+ Functions
+ scope
+ entity.name.function, meta.require, support.function.any-method
+ settings
+
+ foreground
+ #{{base0D-hex}}
+
+
+
+ name
+ Labels
+ scope
+ entity.name.label
+ settings
+
+ foreground
+ #{{base0F-hex}}
+
+
+
+ name
+ Classes
+ scope
+ support.class, entity.name.class, entity.name.type.class, entity.name
+ settings
+
+ foreground
+ #{{base0A-hex}}
+
+
+
+ name
+ Classes
+ scope
+ meta.class
+ settings
+
+ foreground
+ #{{base07-hex}}
+
+
+
+ name
+ Methods
+ scope
+ keyword.other.special-method
+ settings
+
+ foreground
+ #{{base0D-hex}}
+
+
+
+ name
+ Storage
+ scope
+ storage
+ settings
+
+ foreground
+ #{{base0E-hex}}
+
+
+
+ name
+ Support
+ scope
+ support.function
+ settings
+
+ foreground
+ #{{base0C-hex}}
+
+
+
+ name
+ Strings, Inherited Class
+ scope
+ string, constant.other.symbol, entity.other.inherited-class
+ settings
+
+ foreground
+ #{{base0B-hex}}
+
+
+
+ name
+ Integers
+ scope
+ constant.numeric
+ settings
+
+ foreground
+ #{{base09-hex}}
+
+
+
+ name
+ Floats
+ scope
+ none
+ settings
+
+ foreground
+ #{{base09-hex}}
+
+
+
+ name
+ Boolean
+ scope
+ none
+ settings
+
+ foreground
+ #{{base09-hex}}
+
+
+
+ name
+ Constants
+ scope
+ constant
+ settings
+
+ foreground
+ #{{base09-hex}}
+
+
+
+ name
+ Tags
+ scope
+ entity.name.tag
+ settings
+
+ foreground
+ #{{base08-hex}}
+
+
+
+ name
+ Attributes
+ scope
+ entity.other.attribute-name
+ settings
+
+ foreground
+ #{{base09-hex}}
+
+
+
+ name
+ Attribute IDs
+ scope
+ entity.other.attribute-name.id, punctuation.definition.entity
+ settings
+
+ foreground
+ #{{base0D-hex}}
+
+
+
+ name
+ Selector
+ scope
+ meta.selector
+ settings
+
+ foreground
+ #{{base0E-hex}}
+
+
+
+ name
+ Values
+ scope
+ none
+ settings
+
+ foreground
+ #{{base09-hex}}
+
+
+
+ name
+ Headings
+ scope
+ markup.heading, punctuation.definition.heading, entity.name.section
+ settings
+
+ fontStyle
+
+ foreground
+ #{{base0D-hex}}
+
+
+
+ name
+ Units
+ scope
+ keyword.other.unit
+ settings
+
+ foreground
+ #{{base09-hex}}
+
+
+
+ name
+ Bold
+ scope
+ markup.bold, punctuation.definition.bold
+ settings
+
+ fontStyle
+ bold
+ foreground
+ #{{base0A-hex}}
+
+
+
+ name
+ Italic
+ scope
+ markup.italic, punctuation.definition.italic
+ settings
+
+ fontStyle
+ italic
+ foreground
+ #{{base0E-hex}}
+
+
+
+ name
+ Code
+ scope
+ markup.raw.inline
+ settings
+
+ foreground
+ #{{base0B-hex}}
+
+
+
+ name
+ Link Text
+ scope
+ string.other.link, punctuation.definition.string.end.markdown, punctuation.definition.string.begin.markdown
+ settings
+
+ foreground
+ #{{base08-hex}}
+
+
+
+ name
+ Link Url
+ scope
+ meta.link
+ settings
+
+ foreground
+ #{{base09-hex}}
+
+
+
+ name
+ Quotes
+ scope
+ markup.quote
+ settings
+
+ foreground
+ #{{base09-hex}}
+
+
+
+ name
+ Separator
+ scope
+ meta.separator
+ settings
+
+ background
+ #{{base02-hex}}
+ foreground
+ #{{base05-hex}}
+
+
+
+ name
+ Inserted
+ scope
+ markup.inserted
+ settings
+
+ foreground
+ #{{base0B-hex}}
+
+
+
+ name
+ Deleted
+ scope
+ markup.deleted
+ settings
+
+ foreground
+ #{{base08-hex}}
+
+
+
+ name
+ Changed
+ scope
+ markup.changed
+ settings
+
+ foreground
+ #{{base0E-hex}}
+
+
+
+ name
+ Colors
+ scope
+ constant.other.color
+ settings
+
+ foreground
+ #{{base0C-hex}}
+
+
+
+ name
+ Regular Expressions
+ scope
+ string.regexp
+ settings
+
+ foreground
+ #{{base0C-hex}}
+
+
+
+ name
+ Escape Characters
+ scope
+ constant.character.escape
+ settings
+
+ foreground
+ #{{base0C-hex}}
+
+
+
+ name
+ Embedded
+ scope
+ punctuation.section.embedded, variable.interpolation
+ settings
+
+ foreground
+ #{{base0E-hex}}
+
+
+
+ name
+ Illegal
+ scope
+ invalid.illegal
+ settings
+
+ background
+ #{{base08-hex}}
+ foreground
+ #{{base07-hex}}
+
+
+
+ name
+ Broken
+ scope
+ invalid.broken
+ settings
+
+ background
+ #{{base09-hex}}
+ foreground
+ #{{base00-hex}}
+
+
+
+ name
+ Deprecated
+ scope
+ invalid.deprecated
+ settings
+
+ background
+ #{{base0F-hex}}
+ foreground
+ #{{base07-hex}}
+
+
+
+ name
+ Unimplemented
+ scope
+ invalid.unimplemented
+ settings
+
+ background
+ #{{base03-hex}}
+ foreground
+ #{{base07-hex}}
+
+
+
+ uuid
+ uuid
+
+
diff --git a/modules/bat/hm.nix b/modules/bat/hm.nix
new file mode 100644
index 0000000..64ba755
--- /dev/null
+++ b/modules/bat/hm.nix
@@ -0,0 +1,18 @@
+{ config, lib, ... }:
+
+{
+ options.stylix.targets.bat.enable = config.lib.stylix.mkEnableTarget "Bat" true;
+
+ config = lib.mkIf (config.stylix.enable && config.stylix.targets.bat.enable) {
+ programs.bat = {
+ # This theme is reused for yazi. Changes to the template
+ # will need to be applied to modules/yazi/hm.nix
+ themes."base16-stylix".src = config.lib.stylix.colors {
+ template = ./base16-stylix.mustache;
+ extension = ".tmTheme";
+ };
+
+ config.theme = "base16-stylix";
+ };
+ };
+}
diff --git a/modules/bemenu/hm.nix b/modules/bemenu/hm.nix
new file mode 100644
index 0000000..1b2e97a
--- /dev/null
+++ b/modules/bemenu/hm.nix
@@ -0,0 +1,58 @@
+{ config, lib, ... }:
+
+with config.lib.stylix.colors.withHashtag;
+with config.stylix.fonts;
+let
+ bemenuOpacity = lib.toHexString (
+ ((builtins.ceil (config.stylix.opacity.popups * 100)) * 255) / 100
+ );
+in
+{
+ options.stylix.targets.bemenu = {
+ enable = config.lib.stylix.mkEnableTarget "bemenu" true;
+
+ fontSize = lib.mkOption {
+ description = ''
+ Font size used for bemenu.
+ '';
+ type = with lib.types; nullOr int;
+ default = sizes.popups;
+ }; # optional argument
+
+ alternate = lib.mkOption {
+ description = ''
+ Whether to use alternating colours.
+ '';
+ type = lib.types.bool;
+ default = false;
+ };
+ };
+
+ config =
+ lib.mkIf (config.stylix.enable && config.stylix.targets.bemenu.enable)
+ {
+ programs.bemenu.settings = with config.stylix.targets.bemenu; {
+ tb = "${base01}${bemenuOpacity}"; # Title bg
+ nb = "${base01}${bemenuOpacity}"; # Normal bg
+ fb = "${base01}${bemenuOpacity}"; # Filter bg
+ hb = "${base03}${bemenuOpacity}"; # Highlighted bg
+ sb = "${base03}${bemenuOpacity}"; # Selected bg
+ scb = "${base01}"; # Scrollbar bg
+
+ hf = "${base0A}"; # Highlighted fg
+ sf = "${base0B}"; # Selected fg
+ tf = "${base05}"; # Title fg
+ ff = "${base05}"; # Filter fg
+ nf = "${base05}"; # Normal fg
+ scf = "${base03}"; # Scrollbar fg
+
+ ab = "${if alternate then base00 else base01}"; # Alternate bg
+ af = "${if alternate then base04 else base05}"; # Alternate fg
+
+ # Font name
+ fn = "${sansSerif.name} ${
+ lib.optionalString (fontSize != null) (builtins.toString fontSize)
+ }";
+ };
+ };
+}
diff --git a/modules/bspwm/hm.nix b/modules/bspwm/hm.nix
new file mode 100644
index 0000000..36d360d
--- /dev/null
+++ b/modules/bspwm/hm.nix
@@ -0,0 +1,18 @@
+{ config, lib, ... }:
+
+let
+ colors = config.lib.stylix.colors.withHashtag;
+in
+{
+ options.stylix.targets.bspwm.enable =
+ config.lib.stylix.mkEnableTarget "bspwm" true;
+
+ config = lib.mkIf (config.stylix.enable && config.stylix.targets.bspwm.enable) {
+ xsession.windowManager.bspwm.settings = {
+ normal_border_color = colors.base03;
+ active_border_color = colors.base0C;
+ focused_border_color = colors.base0D;
+ presel_feedback_color = colors.base00;
+ };
+ };
+}
diff --git a/modules/btop/hm.nix b/modules/btop/hm.nix
new file mode 100644
index 0000000..35281ff
--- /dev/null
+++ b/modules/btop/hm.nix
@@ -0,0 +1,70 @@
+{ config, lib, ... }:
+
+let
+ colors = config.lib.stylix.colors.withHashtag;
+in
+{
+ options.stylix.targets.btop.enable =
+ config.lib.stylix.mkEnableTarget "btop" true;
+
+ config =
+ lib.mkIf
+ (
+ config.stylix.enable
+ && config.stylix.targets.btop.enable
+ && config.programs.btop.enable
+ )
+ {
+
+ programs.btop.settings = {
+ color_theme = "stylix";
+ theme_background = lib.mkIf (config.stylix.opacity.terminal != 1.0) false;
+ };
+
+ xdg.configFile."btop/themes/stylix.theme".text = with colors; ''
+ #Generated by Stylix
+ theme[main_bg]="${base00}"
+ theme[main_fg]="${base05}"
+ theme[title]="${base05}"
+ theme[hi_fg]="${base0D}"
+ theme[selected_bg]="${base03}"
+ theme[selected_fg]="${base0D}"
+ theme[inactive_fg]="${base04}"
+ theme[graph_text]="${base06}"
+ theme[meter_bg]="${base03}"
+ theme[proc_misc]="${base06}"
+ theme[cpu_box]="${base0E}"
+ theme[mem_box]="${base0B}"
+ theme[net_box]="${base0C}"
+ theme[proc_box]="${base0D}"
+ theme[div_line]="${base01}"
+ theme[temp_start]="${base0B}"
+ theme[temp_mid]="${base0A}"
+ theme[temp_end]="${base08}"
+ theme[cpu_start]="${base0B}"
+ theme[cpu_mid]="${base0A}"
+ theme[cpu_end]="${base08}"
+ theme[free_start]="${base0B}"
+ theme[free_mid]="${base0A}"
+ theme[free_end]="${base08}"
+ theme[cached_start]="${base0B}"
+ theme[cached_mid]="${base0A}"
+ theme[cached_end]="${base08}"
+ theme[available_start]="${base0B}"
+ theme[available_mid]="${base0A}"
+ theme[available_end]="${base08}"
+ theme[used_start]="${base0B}"
+ theme[used_mid]="${base0A}"
+ theme[used_end]="${base08}"
+ theme[download_start]="${base0B}"
+ theme[download_mid]="${base0A}"
+ theme[download_end]="${base08}"
+ theme[upload_start]="${base0B}"
+ theme[upload_mid]="${base0A}"
+ theme[upload_end]="${base08}"
+ theme[process_start]="${base0B}"
+ theme[process_mid]="${base0A}"
+ theme[process_end]="${base08}"
+ '';
+ };
+}
diff --git a/modules/cava/hm.nix b/modules/cava/hm.nix
new file mode 100644
index 0000000..a0bd5dc
--- /dev/null
+++ b/modules/cava/hm.nix
@@ -0,0 +1,43 @@
+{ config, lib, ... }:
+
+let
+
+ mkGradient =
+ colors:
+ lib.listToAttrs (
+ lib.imap0 (
+ i: c: lib.nameValuePair "gradient_color_${toString (i + 1)}" "'#${c}'"
+ ) colors
+ )
+ // {
+ gradient = 1;
+ gradient_count = builtins.length colors;
+ };
+
+ rainbowColors = with config.lib.stylix.colors; [
+ base0E
+ base0D
+ base0C
+ base0B
+ base0A
+ base09
+ base08
+ ];
+
+in
+{
+ options.stylix.targets.cava = {
+ enable = config.lib.stylix.mkEnableTarget "CAVA" true;
+ rainbow.enable = config.lib.stylix.mkEnableTarget "rainbow gradient theming" false;
+ };
+
+ config =
+ let
+ cfg = config.stylix.targets.cava;
+ in
+ lib.mkIf (config.stylix.enable && cfg.enable) {
+ programs.cava.settings.color = lib.mkIf cfg.rainbow.enable (
+ mkGradient rainbowColors
+ );
+ };
+}
diff --git a/modules/chromium/nixos.nix b/modules/chromium/nixos.nix
new file mode 100644
index 0000000..a8fd3b8
--- /dev/null
+++ b/modules/chromium/nixos.nix
@@ -0,0 +1,16 @@
+{ config, lib, ... }:
+
+{
+ options.stylix.targets.chromium.enable =
+ config.lib.stylix.mkEnableTarget "Chromium, Google Chrome and Brave" true;
+
+ config.programs.chromium =
+ lib.mkIf (config.stylix.enable && config.stylix.targets.chromium.enable)
+ {
+ # This enables policies without installing the browser. Policies take up a
+ # negligible amount of space, so it's reasonable to have this always on.
+ enable = true;
+
+ extraOpts.BrowserThemeColor = config.lib.stylix.colors.withHashtag.base00;
+ };
+}
diff --git a/modules/chromium/testbed.nix b/modules/chromium/testbed.nix
new file mode 100644
index 0000000..b45a182
--- /dev/null
+++ b/modules/chromium/testbed.nix
@@ -0,0 +1,15 @@
+{ pkgs, ... }:
+
+let
+ package = pkgs.chromium;
+
+in
+{
+ stylix.testbed.application = {
+ enable = true;
+ name = "chromium-browser";
+ inherit package;
+ };
+
+ environment.systemPackages = [ package ];
+}
diff --git a/modules/console/nixos.nix b/modules/console/nixos.nix
new file mode 100644
index 0000000..5f7b103
--- /dev/null
+++ b/modules/console/nixos.nix
@@ -0,0 +1,29 @@
+{ config, lib, ... }:
+
+with config.lib.stylix.colors;
+
+{
+ options.stylix.targets.console.enable =
+ config.lib.stylix.mkEnableTarget "the Linux kernel console" true;
+
+ config.console.colors =
+ lib.mkIf (config.stylix.enable && config.stylix.targets.console.enable)
+ [
+ base00-hex
+ red
+ green
+ yellow
+ blue
+ magenta
+ cyan
+ base05-hex
+ base03-hex
+ red
+ green
+ yellow
+ blue
+ magenta
+ cyan
+ base06-hex
+ ];
+}
diff --git a/modules/dunst/hm.nix b/modules/dunst/hm.nix
new file mode 100644
index 0000000..85eeaff
--- /dev/null
+++ b/modules/dunst/hm.nix
@@ -0,0 +1,40 @@
+{ config, lib, ... }:
+
+with config.lib.stylix.colors.withHashtag;
+with config.stylix.fonts;
+let
+ dunstOpacity = lib.toHexString (
+ ((builtins.ceil (config.stylix.opacity.popups * 100)) * 255) / 100
+ );
+in
+{
+ options.stylix.targets.dunst.enable =
+ config.lib.stylix.mkEnableTarget "Dunst" true;
+
+ config = lib.mkIf (config.stylix.enable && config.stylix.targets.dunst.enable) {
+ services.dunst.settings = {
+ global = {
+ separator_color = base02;
+ font = "${sansSerif.name} ${toString sizes.popups}";
+ };
+
+ urgency_low = {
+ background = base01 + dunstOpacity;
+ foreground = base05;
+ frame_color = base0B;
+ };
+
+ urgency_normal = {
+ background = base01 + dunstOpacity;
+ foreground = base05;
+ frame_color = base0E;
+ };
+
+ urgency_critical = {
+ background = base01 + dunstOpacity;
+ foreground = base05;
+ frame_color = base08;
+ };
+ };
+ };
+}
diff --git a/modules/emacs/hm.nix b/modules/emacs/hm.nix
new file mode 100644
index 0000000..c090f7a
--- /dev/null
+++ b/modules/emacs/hm.nix
@@ -0,0 +1,83 @@
+{
+ pkgs,
+ config,
+ lib,
+ ...
+}:
+
+with config.lib.stylix.colors.withHashtag;
+with config.stylix.fonts;
+
+let
+ emacsOpacity = builtins.toString (
+ builtins.ceil (config.stylix.opacity.applications * 100)
+ );
+ emacsSize = builtins.toString (sizes.terminal * 1.0);
+in
+{
+ options.stylix.targets.emacs.enable =
+ config.lib.stylix.mkEnableTarget "Emacs" true;
+
+ config = lib.mkIf (config.stylix.enable && config.stylix.targets.emacs.enable) {
+ programs.emacs = {
+ extraPackages = epkgs: [
+ (epkgs.trivialBuild {
+ pname = "base16-stylix-theme";
+ version = "0.1.0";
+ src = pkgs.writeText "base16-stylix-theme.el" ''
+ (require 'base16-theme)
+
+ (defvar base16-stylix-theme-colors
+ '(:base00 "${base00}"
+ :base01 "${base01}"
+ :base02 "${base02}"
+ :base03 "${base03}"
+ :base04 "${base04}"
+ :base05 "${base05}"
+ :base06 "${base06}"
+ :base07 "${base07}"
+ :base08 "${base08}"
+ :base09 "${base09}"
+ :base0A "${base0A}"
+ :base0B "${base0B}"
+ :base0C "${base0C}"
+ :base0D "${base0D}"
+ :base0E "${base0E}"
+ :base0F "${base0F}")
+ "All colors for Base16 stylix are defined here.")
+
+ ;; Define the theme
+ (deftheme base16-stylix)
+
+ ;; Add all the faces to the theme
+ (base16-theme-define 'base16-stylix base16-stylix-theme-colors)
+
+ ;; Mark the theme as provided
+ (provide-theme 'base16-stylix)
+
+ ;; Add path to theme to theme-path
+ (add-to-list 'custom-theme-load-path
+ (file-name-directory
+ (file-truename load-file-name)))
+
+ (provide 'base16-stylix-theme)
+ '';
+ packageRequires = [ epkgs.base16-theme ];
+ })
+ ];
+
+ extraConfig = ''
+ ;; ---- Generated by stylix ----
+ (require 'base16-stylix-theme)
+ (setq base16-theme-256-color-source 'colors)
+ (load-theme 'base16-stylix t)
+ ;; Set font
+ (set-face-attribute 'default nil :font (font-spec :family "${monospace.name}" :size ${emacsSize}))
+ ;; -----------------------------
+ ;; set opacity
+ (add-to-list 'default-frame-alist '(alpha-background . ${emacsOpacity}))
+ ;; -----------------------------
+ '';
+ };
+ };
+}
diff --git a/modules/emacs/testbed.nix b/modules/emacs/testbed.nix
new file mode 100644
index 0000000..ad4116b
--- /dev/null
+++ b/modules/emacs/testbed.nix
@@ -0,0 +1,22 @@
+{ pkgs, ... }:
+
+let
+ package = pkgs.emacs;
+
+in
+{
+ stylix.testbed.application = {
+ enable = true;
+ name = "emacs";
+ inherit package;
+ };
+
+ home-manager.sharedModules = [
+ {
+ programs.emacs = {
+ enable = true;
+ inherit package;
+ };
+ }
+ ];
+}
diff --git a/modules/fcitx5/highlight.svg.mustache b/modules/fcitx5/highlight.svg.mustache
new file mode 100644
index 0000000..783e1c9
--- /dev/null
+++ b/modules/fcitx5/highlight.svg.mustache
@@ -0,0 +1,84 @@
+
+
diff --git a/modules/fcitx5/hm.nix b/modules/fcitx5/hm.nix
new file mode 100644
index 0000000..bef9885
--- /dev/null
+++ b/modules/fcitx5/hm.nix
@@ -0,0 +1,34 @@
+{
+ config,
+ lib,
+ ...
+}:
+let
+ # Adapted from https://github.com/sanweiya/fcitx5-mellow-themes under the BSD 2 license (compatible with this project's license (MIT))
+ theme = config.lib.stylix.colors {
+ template = ./theme.conf.mustache;
+ extension = "conf";
+ };
+ highlight = config.lib.stylix.colors {
+ template = ./highlight.svg.mustache;
+ extension = "svg";
+ };
+ panel = config.lib.stylix.colors {
+ template = ./panel.svg.mustache;
+ extension = "svg";
+ };
+in
+{
+ options.stylix.targets.fcitx5.enable =
+ config.lib.stylix.mkEnableTarget "fcitx5" true;
+
+ config =
+ lib.mkIf (config.stylix.enable && config.stylix.targets.fcitx5.enable)
+ {
+ xdg.dataFile = {
+ "fcitx5/themes/stylix/highlight.svg".source = highlight;
+ "fcitx5/themes/stylix/panel.svg".source = panel;
+ "fcitx5/themes/stylix/theme.conf".source = theme;
+ };
+ };
+}
diff --git a/modules/fcitx5/panel.svg.mustache b/modules/fcitx5/panel.svg.mustache
new file mode 100644
index 0000000..c3e0659
--- /dev/null
+++ b/modules/fcitx5/panel.svg.mustache
@@ -0,0 +1,124 @@
+
+
diff --git a/modules/fcitx5/theme.conf.mustache b/modules/fcitx5/theme.conf.mustache
new file mode 100644
index 0000000..60fa040
--- /dev/null
+++ b/modules/fcitx5/theme.conf.mustache
@@ -0,0 +1,240 @@
+[Metadata]
+Name=Stylix
+Version=0.1
+Author="sanweiya and ontake (make-42)"
+Description="Stylix fcitx5 theme based on the mellow-themes by sanweiya"
+
+[InputPanel]
+NormalColor=#{{base05-hex}}
+HighlightCandidateColor=#{{base04-hex}}
+EnableBlur=False
+BlurMask=
+FullWidthHighlight=True
+HighlightColor=#{{base04-hex}}
+HighlightBackgroundColor=#{{base0E-hex}}
+
+[InputPanel/BlurMargin]
+Left=0
+Right=0
+Top=0
+Bottom=0
+
+[InputPanel/Background]
+Image=panel.svg
+Color=#{{base01-hex}}
+BorderColor=#{{base01-hex}}
+BorderWidth=0
+Overlay=
+Gravity="Top Left"
+OverlayOffsetX=0
+OverlayOffsetY=0
+HideOverlayIfOversize=False
+
+[InputPanel/Background/Margin]
+Left=15
+Right=15
+Top=15
+Bottom=15
+
+[InputPanel/Background/OverlayClipMargin]
+Left=0
+Right=0
+Top=0
+Bottom=0
+
+[InputPanel/Highlight]
+Image=highlight.svg
+Color=#{{base01-hex}}
+BorderColor=#{{base01-hex}}00
+BorderWidth=0
+Overlay=
+Gravity="Top Left"
+OverlayOffsetX=0
+OverlayOffsetY=0
+HideOverlayIfOversize=False
+
+[InputPanel/Highlight/Margin]
+Left=15
+Right=15
+Top=10
+Bottom=10
+
+[InputPanel/Highlight/OverlayClipMargin]
+Left=0
+Right=0
+Top=0
+Bottom=0
+
+[InputPanel/Highlight/HighlightClickMargin]
+Left=0
+Right=0
+Top=0
+Bottom=0
+
+[InputPanel/ContentMargin]
+Left=9
+Right=9
+Top=7
+Bottom=7
+
+[InputPanel/TextMargin]
+Left=9
+Right=9
+Top=6
+Bottom=7
+
+[InputPanel/PrevPage]
+Image=
+
+[InputPanel/PrevPage/ClickMargin]
+Left=5
+Right=5
+Top=4
+Bottom=4
+
+[InputPanel/NextPage]
+Image=
+
+[InputPanel/NextPage/ClickMargin]
+Left=5
+Right=5
+Top=4
+Bottom=4
+
+[InputPanel/ShadowMargin]
+Left=0
+Right=0
+Top=0
+Bottom=0
+
+[Menu]
+NormalColor=#{{base05-hex}}
+HighlightCandidateColor=#{{base02-hex}}
+Spacing=0
+
+[Menu/Background]
+Image=panel.svg
+Color=#{{base01-hex}}
+BorderColor=#{{base01-hex}}00
+BorderWidth=0
+Overlay=
+Gravity="Top Left"
+OverlayOffsetX=0
+OverlayOffsetY=0
+HideOverlayIfOversize=False
+
+[Menu/Background/Margin]
+Left=11
+Right=11
+Top=11
+Bottom=11
+
+[Menu/Background/OverlayClipMargin]
+Left=0
+Right=0
+Top=0
+Bottom=0
+
+[Menu/Highlight]
+Image=highlight.svg
+Color=#{{base05-hex}}
+BorderColor=#{{base05-hex}}00
+BorderWidth=0
+Overlay=
+Gravity="Top Left"
+OverlayOffsetX=0
+OverlayOffsetY=0
+HideOverlayIfOversize=False
+
+[Menu/Highlight/Margin]
+Left=5
+Right=5
+Top=5
+Bottom=5
+
+[Menu/Highlight/OverlayClipMargin]
+Left=0
+Right=0
+Top=0
+Bottom=0
+
+[Menu/Separator]
+Image=
+Color=#{{base00-hex}}
+BorderColor=#{{base00-hex}}00
+BorderWidth=0
+Overlay=
+Gravity="Top Left"
+OverlayOffsetX=0
+OverlayOffsetY=0
+HideOverlayIfOversize=False
+
+[Menu/Separator/Margin]
+Left=0
+Right=0
+Top=0
+Bottom=0
+
+[Menu/Separator/OverlayClipMargin]
+Left=0
+Right=0
+Top=0
+Bottom=0
+
+[Menu/CheckBox]
+Image=radio.svg
+Color=#{{base01-hex}}
+BorderColor=#{{base01-hex}}00
+BorderWidth=0
+Overlay=
+Gravity="Top Left"
+OverlayOffsetX=0
+OverlayOffsetY=0
+HideOverlayIfOversize=False
+
+[Menu/CheckBox/Margin]
+Left=0
+Right=0
+Top=0
+Bottom=0
+
+[Menu/CheckBox/OverlayClipMargin]
+Left=0
+Right=0
+Top=0
+Bottom=0
+
+[Menu/SubMenu]
+Image=arrow.svg
+Color=#{{base01-hex}}
+BorderColor=#{{base01-hex}}00
+BorderWidth=0
+Overlay=
+Gravity="Top Left"
+OverlayOffsetX=0
+OverlayOffsetY=0
+HideOverlayIfOversize=False
+
+[Menu/SubMenu/Margin]
+Left=0
+Right=0
+Top=0
+Bottom=0
+
+[Menu/SubMenu/OverlayClipMargin]
+Left=0
+Right=0
+Top=0
+Bottom=0
+
+[Menu/ContentMargin]
+Left=11
+Right=11
+Top=11
+Bottom=11
+
+[Menu/TextMargin]
+Left=6
+Right=6
+Top=6
+Bottom=6
diff --git a/modules/feh/hm.nix b/modules/feh/hm.nix
new file mode 100644
index 0000000..a101299
--- /dev/null
+++ b/modules/feh/hm.nix
@@ -0,0 +1,44 @@
+{
+ pkgs,
+ config,
+ lib,
+ ...
+}:
+
+{
+ options.stylix.targets.feh.enable =
+ config.lib.stylix.mkEnableTarget "the desktop background using Feh" true;
+
+ config.xsession.initExtra =
+ lib.mkIf
+ (
+ config.stylix.enable
+ && config.stylix.targets.feh.enable
+ && (
+ with config.xsession.windowManager;
+ bspwm.enable
+ || herbstluftwm.enable
+ || i3.enable
+ || spectrwm.enable
+ || xmonad.enable
+ )
+ )
+ (
+ let
+ inherit (config.stylix) imageScalingMode;
+ bg-arg =
+ if imageScalingMode == "fill" then
+ "--bg-fill"
+ else if imageScalingMode == "center" then
+ "--bg-center"
+ else if imageScalingMode == "tile" then
+ "--bg-tile"
+ else if imageScalingMode == "stretch" then
+ "--bg-scale"
+ # Fit
+ else
+ "--bg-max";
+ in
+ "${pkgs.feh}/bin/feh --no-fehbg ${bg-arg} ${config.stylix.image}"
+ );
+}
diff --git a/modules/feh/nixos.nix b/modules/feh/nixos.nix
new file mode 100644
index 0000000..64469e0
--- /dev/null
+++ b/modules/feh/nixos.nix
@@ -0,0 +1,37 @@
+{
+ pkgs,
+ config,
+ lib,
+ ...
+}:
+
+{
+ options.stylix.targets.feh.enable =
+ config.lib.stylix.mkEnableTarget "the desktop background using Feh" true;
+
+ config.services.xserver.displayManager.sessionCommands =
+ lib.mkIf
+ (
+ config.stylix.enable
+ && config.stylix.targets.feh.enable
+ && (with config.services.xserver.windowManager; xmonad.enable || i3.enable)
+ )
+ (
+ let
+ inherit (config.stylix) imageScalingMode;
+ bg-arg =
+ if imageScalingMode == "fill" then
+ "--bg-fill"
+ else if imageScalingMode == "center" then
+ "--bg-center"
+ else if imageScalingMode == "tile" then
+ "--bg-tile"
+ else if imageScalingMode == "stretch" then
+ "--bg-scale"
+ # Fit
+ else
+ "--bg-max";
+ in
+ "${pkgs.feh}/bin/feh --no-fehbg ${bg-arg} ${config.stylix.image}"
+ );
+}
diff --git a/modules/firefox/hm.nix b/modules/firefox/hm.nix
new file mode 100644
index 0000000..d4f30e4
--- /dev/null
+++ b/modules/firefox/hm.nix
@@ -0,0 +1,53 @@
+# Consider also updating the LibreWolf module when updating this module,
+# as they are very similar.
+
+{ config, lib, ... }:
+
+let
+ profileSettings = {
+ settings = {
+ "font.name.monospace.x-western" = config.stylix.fonts.monospace.name;
+ "font.name.sans-serif.x-western" = config.stylix.fonts.sansSerif.name;
+ "font.name.serif.x-western" = config.stylix.fonts.serif.name;
+ };
+ };
+ makeProfileSettingsPair =
+ profileName: lib.nameValuePair profileName profileSettings;
+ derivatives = [
+ {
+ path = "firefox";
+ name = "Firefox";
+ }
+ {
+ path = "librewolf";
+ name = "LibreWolf";
+ }
+ ];
+in
+{
+ options.stylix.targets = lib.listToAttrs (
+ map (
+ drv:
+ lib.nameValuePair drv.path {
+ enable = config.lib.stylix.mkEnableTarget drv.name true;
+
+ profileNames = lib.mkOption {
+ description = "The ${drv.name} profile names to apply styling on.";
+ type = lib.types.listOf lib.types.str;
+ default = [ ];
+ };
+ }
+ ) derivatives
+ );
+
+ config = lib.mkMerge (
+ map (
+ drv:
+ lib.mkIf (config.stylix.enable && config.stylix.targets.${drv.path}.enable) {
+ programs.${drv.path}.profiles = lib.listToAttrs (
+ map makeProfileSettingsPair config.stylix.targets.${drv.path}.profileNames
+ );
+ }
+ ) derivatives
+ );
+}
diff --git a/modules/firefox/testbed.nix b/modules/firefox/testbed.nix
new file mode 100644
index 0000000..fb10610
--- /dev/null
+++ b/modules/firefox/testbed.nix
@@ -0,0 +1,25 @@
+{ pkgs, ... }:
+
+let
+ package = pkgs.firefox;
+
+in
+{
+ stylix.testbed.application = {
+ enable = true;
+ name = "firefox";
+ inherit package;
+ };
+
+ home-manager.sharedModules = [
+ {
+ programs.firefox = {
+ enable = true;
+ inherit package;
+ profiles.stylix.isDefault = true;
+ };
+
+ stylix.targets.firefox.profileNames = [ "stylix" ];
+ }
+ ];
+}
diff --git a/modules/fish/hm.nix b/modules/fish/hm.nix
new file mode 100644
index 0000000..4493aec
--- /dev/null
+++ b/modules/fish/hm.nix
@@ -0,0 +1,10 @@
+{ config, lib, ... }:
+
+{
+ options.stylix.targets.fish.enable =
+ config.lib.stylix.mkEnableTarget "Fish" true;
+
+ config = lib.mkIf (config.stylix.enable && config.stylix.targets.fish.enable) {
+ programs.fish.interactiveShellInit = import ./prompt.nix config;
+ };
+}
diff --git a/modules/fish/nixos.nix b/modules/fish/nixos.nix
new file mode 100644
index 0000000..2fa26dd
--- /dev/null
+++ b/modules/fish/nixos.nix
@@ -0,0 +1,10 @@
+{ config, lib, ... }:
+
+{
+ options.stylix.targets.fish.enable =
+ config.lib.stylix.mkEnableTarget "Fish" true;
+
+ config = lib.mkIf (config.stylix.enable && config.stylix.targets.fish.enable) {
+ programs.fish.promptInit = import ./prompt.nix config;
+ };
+}
diff --git a/modules/fish/prompt.nix b/modules/fish/prompt.nix
new file mode 100644
index 0000000..c07ea29
--- /dev/null
+++ b/modules/fish/prompt.nix
@@ -0,0 +1,15 @@
+config:
+
+let
+ theme = config.lib.stylix.colors {
+ templateRepo = config.lib.stylix.templates.base16-fish;
+ };
+in
+''
+ source ${theme}
+
+ # See https://github.com/tomyun/base16-fish/issues/7 for why this condition exists
+ if status --is-interactive && test -z "$TMUX"
+ base16-${config.lib.stylix.colors.slug}
+ end
+''
diff --git a/modules/foot/hm.nix b/modules/foot/hm.nix
new file mode 100644
index 0000000..7c55265
--- /dev/null
+++ b/modules/foot/hm.nix
@@ -0,0 +1,25 @@
+{ config, lib, ... }:
+
+let
+ cfg = config.stylix.targets.foot;
+
+ theme = config.lib.stylix.colors {
+ templateRepo = config.lib.stylix.templates.tinted-foot;
+ };
+
+in
+{
+ options.stylix.targets.foot.enable =
+ config.lib.stylix.mkEnableTarget "Foot" true;
+
+ config.programs.foot.settings = lib.mkIf cfg.enable {
+ main = {
+ include = theme;
+ font =
+ with config.stylix.fonts;
+ "${monospace.name}:size=${toString sizes.terminal}";
+ dpi-aware = "no";
+ };
+ colors.alpha = with config.stylix.opacity; terminal;
+ };
+}
diff --git a/modules/foot/testbed.nix b/modules/foot/testbed.nix
new file mode 100644
index 0000000..072bc27
--- /dev/null
+++ b/modules/foot/testbed.nix
@@ -0,0 +1,22 @@
+{ pkgs, ... }:
+
+let
+ package = pkgs.foot;
+
+in
+{
+ stylix.testbed.application = {
+ enable = true;
+ name = "foot";
+ inherit package;
+ };
+
+ home-manager.sharedModules = [
+ {
+ programs.foot = {
+ enable = true;
+ inherit package;
+ };
+ }
+ ];
+}
diff --git a/modules/forge/hm.nix b/modules/forge/hm.nix
new file mode 100644
index 0000000..03b4932
--- /dev/null
+++ b/modules/forge/hm.nix
@@ -0,0 +1,15 @@
+{ config, lib, ... }:
+
+{
+ options.stylix.targets.forge.enable =
+ config.lib.stylix.mkEnableTarget "Forge" true;
+
+ config = lib.mkIf (config.stylix.enable && config.stylix.targets.forge.enable) {
+ xdg.configFile."forge/stylesheet/forge/stylesheet.css".source =
+ config.lib.stylix.colors
+ {
+ template = ./stylesheet.css.mustache;
+ extension = ".css";
+ };
+ };
+}
diff --git a/modules/forge/stylesheet.css.mustache b/modules/forge/stylesheet.css.mustache
new file mode 100644
index 0000000..25a9608
--- /dev/null
+++ b/modules/forge/stylesheet.css.mustache
@@ -0,0 +1,140 @@
+.tiled {
+ color: #{{base0D-hex}};
+ opacity: 1;
+ border-width: 3px;
+}
+
+.split {
+ color: #{{base0D-hex}};
+ opacity: 1;
+ border-width: 3px;
+}
+
+.stacked {
+ color: #{{base0D-hex}};
+ opacity: 1;
+ border-width: 3px;
+}
+
+.tabbed {
+ color: #{{base0D-hex}};
+ opacity: 1;
+ border-width: 3px;
+}
+
+.floated {
+ color: #{{base0D-hex}};
+ border-width: 3px;
+ opacity: 1;
+}
+
+.window-tiled-border {
+ border-width: 3px;
+ border-color: #{{base0D-hex}};
+ border-style: solid;
+ border-radius: 14px;
+}
+
+.window-split-border {
+ border-width: 3px;
+ border-color: #{{base0D-hex}};
+ border-style: solid;
+ border-radius: 14px;
+}
+
+.window-split-horizontal {
+ border-left-width: 0;
+ border-top-width: 0;
+ border-bottom-width: 0;
+}
+
+.window-split-vertical {
+ border-left-width: 0;
+ border-top-width: 0;
+ border-right-width: 0;
+}
+
+.window-stacked-border {
+ border-width: 3px;
+ border-color: #{{base0D-hex}};
+ border-style: solid;
+ border-radius: 14px;
+}
+
+.window-tabbed-border {
+ border-width: 3px;
+ border-color: #{{base0D-hex}};
+ border-style: solid;
+ border-radius: 14px;
+}
+
+.window-tabbed-bg {
+ border-radius: 8px;
+}
+
+.window-tabbed-tab {
+ background-color: rgba(54, 47, 45, 1);
+ border-color: #{{base0D-hex}}9A;
+ border-width: 1px;
+ border-radius: 8px;
+ color: white;
+ margin: 1px;
+ box-shadow: 0 0 0 1px rgba(1px 0, 0, 0, 0.2);
+}
+
+.window-tabbed-tab-active {
+ background-color: #{{base0D-hex}};
+ color: black;
+ box-shadow: 0 0 0 1px rgba(1px 0, 0, 0, 0.2);
+}
+
+.window-tabbed-tab-close {
+ padding: 3px;
+ margin: 4px;
+ border-radius: 16px;
+ width: 16px;
+ background-color: #{{base08-hex}};
+}
+
+.window-tabbed-tab-icon {
+ margin: 3px;
+}
+
+.window-floated-border {
+ border-width: 3px;
+ border-color: #{{base0D-hex}};
+ border-style: solid;
+ border-radius: 14px;
+}
+
+.window-tilepreview-tiled {
+ border-width: 1px;
+ border-color: #{{base0D-hex}}4D;
+ border-style: solid;
+ border-radius: 14px;
+ background-color: #{{base0D-hex}}33;
+}
+
+.window-tilepreview-stacked {
+ border-width: 1px;
+ border-color: #{{base0D-hex}}66;
+ border-style: solid;
+ border-radius: 14px;
+ background-color: #{{base0D-hex}}4D;
+}
+
+.window-tilepreview-swap {
+ border-width: 1px;
+ border-color: #{{base0D-hex}}4D;
+ border-style: solid;
+ border-radius: 14px;
+ background-color: #{{base0D-hex}}4D;
+}
+
+.window-tilepreview-tabbed {
+ border-width: 1px;
+ border-color: #{{base0D-hex}}4D;
+ border-style: solid;
+ border-radius: 14px;
+ background-color: #{{base0D-hex}}4D;
+}
diff --git a/modules/fuzzel/hm.nix b/modules/fuzzel/hm.nix
new file mode 100644
index 0000000..af11b50
--- /dev/null
+++ b/modules/fuzzel/hm.nix
@@ -0,0 +1,34 @@
+{ config, lib, ... }:
+
+with config.lib.stylix.colors;
+
+let
+ opacity = lib.toHexString (builtins.ceil (config.stylix.opacity.popups * 255));
+
+in
+{
+ options.stylix.targets.fuzzel.enable =
+ config.lib.stylix.mkEnableTarget "Fuzzel" true;
+
+ config.programs.fuzzel.settings =
+ lib.mkIf (config.stylix.enable && config.stylix.targets.fuzzel.enable)
+ {
+ colors = {
+ background = "${base00-hex}${opacity}";
+ text = "${base05-hex}ff";
+ placeholder = "${base03-hex}ff";
+ prompt = "${base05-hex}ff";
+ input = "${base05-hex}ff";
+ match = "${base0A-hex}ff";
+ selection = "${base03-hex}ff";
+ selection-text = "${base05-hex}ff";
+ selection-match = "${base0A-hex}ff";
+ counter = "${base06-hex}ff";
+ border = "${base0D-hex}ff";
+ };
+
+ main = {
+ font = "${config.stylix.fonts.sansSerif.name}:size=${toString config.stylix.fonts.sizes.popups}";
+ };
+ };
+}
diff --git a/modules/fzf/hm.nix b/modules/fzf/hm.nix
new file mode 100644
index 0000000..28ca4c5
--- /dev/null
+++ b/modules/fzf/hm.nix
@@ -0,0 +1,23 @@
+{ config, lib, ... }:
+{
+ options.stylix.targets.fzf = {
+ enable = config.lib.stylix.mkEnableTarget "Fzf" true;
+ };
+
+ config = lib.mkIf (config.stylix.enable && config.stylix.targets.fzf.enable) {
+ programs.fzf.colors = with config.lib.stylix.colors.withHashtag; {
+ "bg" = base00;
+ "bg+" = base01;
+ "fg" = base04;
+ "fg+" = base06;
+ "header" = base0D;
+ "hl" = base0D;
+ "hl+" = base0D;
+ "info" = base0A;
+ "marker" = base0C;
+ "pointer" = base0C;
+ "prompt" = base0A;
+ "spinner" = base0C;
+ };
+ };
+}
diff --git a/modules/gedit/hm.nix b/modules/gedit/hm.nix
new file mode 100644
index 0000000..03041d2
--- /dev/null
+++ b/modules/gedit/hm.nix
@@ -0,0 +1,19 @@
+{ config, lib, ... }:
+
+let
+ style = config.lib.stylix.colors {
+ template = ./template.mustache;
+ extension = "xml";
+ };
+
+in
+{
+ options.stylix.targets.gedit.enable =
+ config.lib.stylix.mkEnableTarget "GEdit" true;
+
+ config = lib.mkIf (config.stylix.enable && config.stylix.targets.gedit.enable) {
+ xdg.dataFile = {
+ "gedit/styles/stylix.xml".source = style;
+ };
+ };
+}
diff --git a/modules/gedit/template.mustache b/modules/gedit/template.mustache
new file mode 100644
index 0000000..e8a4ed0
--- /dev/null
+++ b/modules/gedit/template.mustache
@@ -0,0 +1,117 @@
+
+
+
+ Stylix
+ <_description>Theme configured as part of your NixOS configuration.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/modules/gedit/testbed.nix b/modules/gedit/testbed.nix
new file mode 100644
index 0000000..8e2e3eb
--- /dev/null
+++ b/modules/gedit/testbed.nix
@@ -0,0 +1,15 @@
+{ pkgs, ... }:
+
+let
+ package = pkgs.gedit;
+
+in
+{
+ stylix.testbed.application = {
+ enable = true;
+ name = "org.gnome.gedit";
+ inherit package;
+ };
+
+ environment.systemPackages = [ package ];
+}
diff --git a/modules/ghostty/hm.nix b/modules/ghostty/hm.nix
new file mode 100644
index 0000000..80518f7
--- /dev/null
+++ b/modules/ghostty/hm.nix
@@ -0,0 +1,58 @@
+# Documentation is available at:
+# - https://ghostty.org/docs/config/reference
+# - `man 5 ghostty`
+{ config, lib, ... }:
+{
+ options.stylix.targets.ghostty.enable =
+ config.lib.stylix.mkEnableTarget "Ghostty" true;
+
+ config =
+ lib.mkIf (config.stylix.enable && config.stylix.targets.ghostty.enable)
+ {
+ programs.ghostty = {
+ settings =
+ let
+ inherit (config.stylix) fonts opacity;
+ in
+ {
+ theme = "stylix";
+ font-family = [
+ fonts.monospace.name
+ fonts.emoji.name
+ ];
+ font-size = fonts.sizes.terminal;
+ background-opacity = opacity.terminal;
+ };
+ themes.stylix =
+ let
+ inherit (config.lib.stylix) colors;
+ inherit (config.lib.stylix.colors) withHashtag;
+ in
+ {
+ palette = [
+ "0=${withHashtag.base03}"
+ "1=${withHashtag.base08}"
+ "2=${withHashtag.base0B}"
+ "3=${withHashtag.base0A}"
+ "4=${withHashtag.base0D}"
+ "5=${withHashtag.base0F}"
+ "6=${withHashtag.base0C}"
+ "7=${withHashtag.base05}"
+ "8=${withHashtag.base04}"
+ "9=${withHashtag.base08}"
+ "10=${withHashtag.base0B}"
+ "11=${withHashtag.base0A}"
+ "12=${withHashtag.base0D}"
+ "13=${withHashtag.base0F}"
+ "14=${withHashtag.base0C}"
+ "15=${withHashtag.base05}"
+ ];
+ background = colors.base00;
+ foreground = colors.base05;
+ cursor-color = colors.base06;
+ selection-background = colors.base02;
+ selection-foreground = colors.base05;
+ };
+ };
+ };
+}
diff --git a/modules/ghostty/testbed.nix b/modules/ghostty/testbed.nix
new file mode 100644
index 0000000..5005de1
--- /dev/null
+++ b/modules/ghostty/testbed.nix
@@ -0,0 +1,20 @@
+{ pkgs, ... }:
+let
+ package = pkgs.ghostty;
+in
+{
+ stylix.testbed.application = {
+ enable = true;
+ name = "com.mitchellh.ghostty";
+ inherit package;
+ };
+
+ home-manager.sharedModules = [
+ {
+ programs.ghostty = {
+ enable = true;
+ inherit package;
+ };
+ }
+ ];
+}
diff --git a/modules/gitui/hm.nix b/modules/gitui/hm.nix
new file mode 100644
index 0000000..ec939f5
--- /dev/null
+++ b/modules/gitui/hm.nix
@@ -0,0 +1,45 @@
+{ config, lib, ... }:
+let
+ inherit (config.lib.stylix) colors;
+
+ mkRgb =
+ color:
+ let
+ r = colors."${color}-rgb-r";
+ g = colors."${color}-rgb-g";
+ b = colors."${color}-rgb-b";
+ in
+ "Rgb(${r}, ${g}, ${b})";
+in
+{
+ options.stylix.targets.gitui.enable =
+ config.lib.stylix.mkEnableTarget "GitUI" true;
+
+ config = lib.mkIf (config.stylix.enable && config.stylix.targets.gitui.enable) {
+ programs.gitui.theme = ''
+ (
+ selected_tab: Some(Reset),
+ command_fg: Some(${mkRgb "base05"}),
+ selection_bg: Some(${mkRgb "base04"}),
+ selection_fg: Some(${mkRgb "base05"}),
+ cmdbar_bg: Some(${mkRgb "base01"}),
+ cmdbar_extra_lines_bg: Some(${mkRgb "base01"}),
+ disabled_fg: Some(${mkRgb "base04"}),
+ diff_line_add: Some(${mkRgb "base0B"}),
+ diff_line_delete: Some(${mkRgb "base08"}),
+ diff_file_added: Some(${mkRgb "base0A"}),
+ diff_file_removed: Some(${mkRgb "base08"}),
+ diff_file_moved: Some(${mkRgb "base0E"}),
+ diff_file_modified: Some(${mkRgb "base09"}),
+ commit_hash: Some(${mkRgb "base07"}),
+ commit_time: Some(${mkRgb "base05"}),
+ commit_author: Some(${mkRgb "base0D"}),
+ danger_fg: Some(${mkRgb "base08"}),
+ push_gauge_bg: Some(${mkRgb "base0D"}),
+ push_gauge_fg: Some(${mkRgb "base00"}),
+ tag_fg: Some(${mkRgb "base06"}),
+ branch_fg: Some(${mkRgb "base0C"})
+ )
+ '';
+ };
+}
diff --git a/modules/gnome/colors.mustache b/modules/gnome/colors.mustache
new file mode 100644
index 0000000..3867c37
--- /dev/null
+++ b/modules/gnome/colors.mustache
@@ -0,0 +1,84 @@
+// _default-colors.scss
+
+$destructive_bg_color: #{{base08-hex}};
+$destructive_fg_color: #{{base00-hex}};
+$destructive_color: #{{base08-hex}};
+
+$success_bg_color: #{{base0B-hex}};
+$success_fg_color: #{{base00-hex}};
+$success_color: #{{base0B-hex}};
+
+$warning_bg_color: #{{base0A-hex}};
+$warning_fg_color: #{{base00-hex}};
+$warning_color: #{{base0A-hex}};
+
+$error_bg_color: #{{base08-hex}};
+$error_fg_color: #{{base00-hex}};
+$error_color: #{{base08-hex}};
+
+$selected_bg_color: #{{base0D-hex}};
+$selected_fg_color: #{{base00-hex}};
+
+$link_color: #{{base0D-hex}};
+$link_visited_color: transparentize($link_color, 0.4);
+
+$background_mix_factor: 0%;
+$border_opacity: 1;
+
+$shadow_color: transparent;
+$text_shadow_color: transparent;
+
+$focus_color: $selected_bg_color;
+$focus_border_color: transparentize(#{{base05-hex}}, 0.5);
+
+// _colors.scss
+
+$base_color: #{{base01-hex}};
+$bg_color: #{{base00-hex}};
+$fg_color: #{{base05-hex}};
+
+$osd_fg_color: #{{base05-hex}};
+$osd_bg_color: #{{base01-hex}};
+
+$system_base_color: #{{base00-hex}};
+$system_fg_color: #{{base05-hex}};
+
+$panel_bg_color: #{{base01-hex}};
+$panel_fg_color: #{{base05-hex}};
+
+$card_bg_color: #{{base01-hex}};
+$card_shadow_color: transparent;
+$card_shadow_border_color: transparent;
+
+$borders_color: transparentize(#{{base05-hex}}, 0.8);
+$outer_borders_color: transparentize(#{{base05-hex}}, 0.9);
+
+$osd_borders_color: $borders_color;
+$osd_outer_borders_color: $outer_borders_color;
+
+$system_bg_color: #{{base00-hex}};
+$system_borders_color: $borders_color;
+$system_insensitive_fg_color: #{{base05-hex}};
+$system_overlay_bg_color: #{{base01-hex}};
+
+$insensitive_fg_color: #{{base04-hex}};
+$insensitive_bg_color: #{{base00-hex}};
+$insensitive_borders_color: $borders_color;
+
+$checked_bg_color: #{{base01-hex}};
+$checked_fg_color: #{{base05-hex}};
+
+$hover_bg_color: #{{base01-hex}};
+$hover_fg_color: #{{base05-hex}};
+
+$active_bg_color: #{{base01-hex}};
+$active_fg_color: #{{base05-hex}};
+
+$accent_borders_color: transparentize(#{{base0D-hex}}, 0.5);
+
+// Other required variables
+
+$_base_color_light: #eeeeee;
+$light_1: #ffffff;
+$red_4: #{{base08-hex}};
+$orange_4: #{{base09-hex}};
diff --git a/modules/gnome/hm.nix b/modules/gnome/hm.nix
new file mode 100644
index 0000000..ac50b07
--- /dev/null
+++ b/modules/gnome/hm.nix
@@ -0,0 +1,74 @@
+{
+ pkgs,
+ config,
+ lib,
+ ...
+}:
+
+let
+ inherit (config.stylix.fonts) sansSerif serif monospace;
+ fontSize = toString config.stylix.fonts.sizes.applications;
+ documentFontSize = toString (config.stylix.fonts.sizes.applications - 1);
+
+in
+{
+ options.stylix.targets.gnome.enable =
+ config.lib.stylix.mkEnableTarget "GNOME" true;
+
+ config = lib.mkIf (config.stylix.enable && config.stylix.targets.gnome.enable) {
+ dconf.settings = {
+ "org/gnome/desktop/background" = {
+ color-shading-type = "solid";
+ picture-options =
+ let
+ inherit (config.stylix) imageScalingMode;
+ in
+ if imageScalingMode == "fit" then
+ "scaled"
+ else if imageScalingMode == "fill" then
+ "zoom"
+ else if imageScalingMode == "stretch" then
+ "stretched"
+ else if imageScalingMode == "center" then
+ "centered"
+ # Seemingly no tile support... :(
+ else
+ "zoom";
+ picture-uri = "file://${config.stylix.image}";
+ picture-uri-dark = "file://${config.stylix.image}";
+ };
+
+ "org/gnome/desktop/interface" = {
+ # We show the same colours regardless of this setting, and the quick
+ # settings tile is removed. The value is still used by Epiphany to
+ # request dark mode for websites which support it.
+ color-scheme =
+ if config.stylix.polarity == "dark" then "prefer-dark" else "default";
+
+ # Some GTK apps will use these font settings if they exist.
+ # i.e emacs-pgtk.
+ font-name = "${sansSerif.name} ${fontSize}";
+ document-font-name = "${serif.name} ${documentFontSize}";
+ monospace-font-name = "${monospace.name} ${fontSize}";
+ };
+
+ "org/gnome/shell/extensions/user-theme".name = "Stylix";
+ };
+
+ xdg.dataFile."themes/Stylix/gnome-shell/gnome-shell.css" = {
+ source =
+ let
+ theme = pkgs.callPackage ./theme.nix {
+ inherit (config.lib.stylix) colors templates;
+ };
+ in
+ "${theme}/share/gnome-shell/gnome-shell.css";
+ onChange = ''
+ if [[ -x "$(command -v gnome-extensions)" ]]; then
+ gnome-extensions disable user-theme@gnome-shell-extensions.gcampax.github.com
+ gnome-extensions enable user-theme@gnome-shell-extensions.gcampax.github.com
+ fi
+ '';
+ };
+ };
+}
diff --git a/modules/gnome/nixos.nix b/modules/gnome/nixos.nix
new file mode 100644
index 0000000..63887a5
--- /dev/null
+++ b/modules/gnome/nixos.nix
@@ -0,0 +1,68 @@
+{
+ lib,
+ pkgs,
+ config,
+ ...
+}:
+
+let
+ theme = pkgs.callPackage ./theme.nix {
+ inherit (config.lib.stylix) colors templates;
+ };
+
+in
+{
+ options.stylix.targets.gnome.enable =
+ config.lib.stylix.mkEnableTarget "GNOME and GDM" true;
+
+ config =
+ lib.mkIf
+ (
+ config.stylix.enable
+ && config.stylix.targets.gnome.enable
+ && (
+ config.services.xserver.desktopManager.gnome.enable
+ || config.services.xserver.displayManager.gdm.enable
+ )
+ )
+ {
+ # As Stylix is controlling the wallpaper, there is no need for this
+ # pack of default wallpapers to be installed.
+ # If you want to use one, you can set stylix.image to something like
+ # "${pkgs.gnome-backgrounds}/path/to/your/preferred/background"
+ # which will then download the pack regardless of its exclusion below.
+ environment.gnome.excludePackages = [ pkgs.gnome-backgrounds ];
+
+ nixpkgs.overlays = [
+ (_: super: {
+ gnome-shell = super.gnome-shell.overrideAttrs (oldAttrs: {
+ # Themes are usually applied via an extension, but extensions are
+ # not available on the login screen. The only way to change the
+ # theme there is by replacing the default.
+ postFixup =
+ (oldAttrs.postFixup or "")
+ + ''
+ cp ${theme}/share/gnome-shell/gnome-shell-theme.gresource \
+ $out/share/gnome-shell/gnome-shell-theme.gresource
+ '';
+ patches = (oldAttrs.patches or [ ]) ++ [
+ ./shell_remove_dark_mode.patch
+ ];
+ });
+ })
+ ];
+
+ # Cursor settings are usually applied via Home Manager,
+ # but the login screen uses a separate database.
+ environment.systemPackages = [ config.stylix.cursor.package ];
+ programs.dconf.profiles.gdm.databases = [
+ {
+ lockAll = true;
+ settings."org/gnome/desktop/interface" = {
+ cursor-theme = config.stylix.cursor.name;
+ cursor-size = lib.gvariant.mkInt32 config.stylix.cursor.size;
+ };
+ }
+ ];
+ };
+}
diff --git a/modules/gnome/shell_colors.patch b/modules/gnome/shell_colors.patch
new file mode 100644
index 0000000..0c2ba1e
--- /dev/null
+++ b/modules/gnome/shell_colors.patch
@@ -0,0 +1,40 @@
+diff --git a/data/gnome-shell-theme.gresource.xml b/data/gnome-shell-theme.gresource.xml
+index 8a4948e41..955ed5b13 100644
+--- a/data/gnome-shell-theme.gresource.xml
++++ b/data/gnome-shell-theme.gresource.xml
+@@ -11,7 +11,6 @@
+ checkbox-off.svg
+ gnome-shell-dark.css
+ gnome-shell-light.css
+- gnome-shell-high-contrast.css
+ gnome-shell-start.svg
+ pad-osd.css
+ process-working.svg
+diff --git a/data/theme/gnome-shell-sass/_common.scss b/data/theme/gnome-shell-sass/_common.scss
+index 5b117ea71..67e7ce756 100644
+--- a/data/theme/gnome-shell-sass/_common.scss
++++ b/data/theme/gnome-shell-sass/_common.scss
+@@ -168,9 +168,9 @@ stage {
+
+ // tooltip
+ %tooltip {
+- background-color: transparentize(black, 0.1);
+- border: 1px solid transparentize($light_1, 0.9);
+- color: $light_1;
++ background-color: transparentize($bg_color, 0.1);
++ border: 1px solid transparentize($base_color, 0.9);
++ color: $fg_color;
+
+ border-radius: 99px;
+ padding: $base_padding $base_padding * 2;
+diff --git a/data/theme/gnome-shell-sass/widgets/_calendar.scss b/data/theme/gnome-shell-sass/widgets/_calendar.scss
+index fc054da38..8e31741c1 100644
+--- a/data/theme/gnome-shell-sass/widgets/_calendar.scss
++++ b/data/theme/gnome-shell-sass/widgets/_calendar.scss
+@@ -27,6 +27,8 @@
+ .date-label {
+ @extend %title_2;
+ }
++
++ color: $fg_color !important;
+ }
diff --git a/modules/gnome/shell_remove_dark_mode.patch b/modules/gnome/shell_remove_dark_mode.patch
new file mode 100644
index 0000000..142ac49
--- /dev/null
+++ b/modules/gnome/shell_remove_dark_mode.patch
@@ -0,0 +1,36 @@
+diff --git a/js/ui/panel.js b/js/ui/panel.js
+index 9f4313b54..9deebbcf9 100644
+--- a/js/ui/panel.js
++++ b/js/ui/panel.js
+@@ -30,7 +30,6 @@ import * as BrightnessStatus from './status/brightness.js';
+ import * as SystemStatus from './status/system.js';
+ import * as LocationStatus from './status/location.js';
+ import * as NightLightStatus from './status/nightLight.js';
+-import * as DarkModeStatus from './status/darkMode.js';
+ import * as BacklightStatus from './status/backlight.js';
+ import * as ThunderboltStatus from './status/thunderbolt.js';
+ import * as AutoRotateStatus from './status/autoRotate.js';
+@@ -546,7 +545,6 @@ class QuickSettings extends PanelMenu.Button {
+ this._location = new LocationStatus.Indicator();
+ this._thunderbolt = new ThunderboltStatus.Indicator();
+ this._nightLight = new NightLightStatus.Indicator();
+- this._darkMode = new DarkModeStatus.Indicator();
+ this._backlight = new BacklightStatus.Indicator();
+ this._powerProfiles = new PowerProfileStatus.Indicator();
+ this._rfkill = new RFKillStatus.Indicator();
+@@ -567,7 +565,6 @@ class QuickSettings extends PanelMenu.Button {
+ this._indicators.add_child(this._nightLight);
+ if (this._network)
+ this._indicators.add_child(this._network);
+- this._indicators.add_child(this._darkMode);
+ this._indicators.add_child(this._backlight);
+ this._indicators.add_child(this._powerProfiles);
+ if (this._bluetooth)
+@@ -599,7 +596,6 @@ class QuickSettings extends PanelMenu.Button {
+ this._addItemsBefore(this._bluetooth.quickSettingsItems, sibling);
+ this._addItemsBefore(this._powerProfiles.quickSettingsItems, sibling);
+ this._addItemsBefore(this._nightLight.quickSettingsItems, sibling);
+- this._addItemsBefore(this._darkMode.quickSettingsItems, sibling);
+ this._addItemsBefore(this._backlight.quickSettingsItems, sibling);
+ this._addItemsBefore(this._rfkill.quickSettingsItems, sibling);
+ this._addItemsBefore(this._autoRotate.quickSettingsItems, sibling);
diff --git a/modules/gnome/testbed.nix b/modules/gnome/testbed.nix
new file mode 100644
index 0000000..fa3a15c
--- /dev/null
+++ b/modules/gnome/testbed.nix
@@ -0,0 +1,7 @@
+{
+ services.xserver = {
+ enable = true;
+ desktopManager.gnome.enable = true;
+ displayManager.gdm.enable = true;
+ };
+}
diff --git a/modules/gnome/theme.nix b/modules/gnome/theme.nix
new file mode 100644
index 0000000..c4bd8c9
--- /dev/null
+++ b/modules/gnome/theme.nix
@@ -0,0 +1,43 @@
+{
+ stdenv,
+ sass,
+ glib,
+ colors,
+ templates,
+}:
+
+let
+ colorsScss = colors {
+ template = ./colors.mustache;
+ extension = "scss";
+ };
+
+in
+stdenv.mkDerivation {
+ name = "${colors.slug}-gnome-shell-theme";
+ src = templates.gnome-shell;
+ patches = [ ./shell_colors.patch ];
+ postPatch = ''
+ rm data/theme/gnome-shell-sass/{_colors.scss,_default-colors.scss,_palette.scss}
+ cp ${colorsScss} data/theme/gnome-shell-sass/_colors.scss
+ '';
+
+ nativeBuildInputs = [
+ sass
+ glib.dev
+ ];
+ buildPhase = ''
+ sass data/theme/gnome-shell-light.scss \
+ >data/theme/gnome-shell-light.css
+ cp data/theme/gnome-shell-{light,dark}.css
+ glib-compile-resources \
+ --sourcedir=data/theme \
+ data/gnome-shell-theme.gresource.xml
+ '';
+
+ installPhase = ''
+ mkdir -p $out/share/gnome-shell
+ mv data/theme/gnome-shell-light.css $out/share/gnome-shell/gnome-shell.css
+ mv data/gnome-shell-theme.gresource $out/share/gnome-shell/gnome-shell-theme.gresource
+ '';
+}
diff --git a/modules/grub/nixos.nix b/modules/grub/nixos.nix
new file mode 100644
index 0000000..d49cc1c
--- /dev/null
+++ b/modules/grub/nixos.nix
@@ -0,0 +1,140 @@
+{
+ pkgs,
+ config,
+ lib,
+ ...
+}:
+
+with config.lib.stylix;
+with config.stylix.fonts;
+with config.lib.stylix.colors.withHashtag;
+
+let
+ # Grub requires fonts to be converted to "PFF2 format"
+ # This function takes a font { name, package } and produces a .pf2 file
+ mkGrubFont =
+ font:
+ pkgs.runCommand "${font.package.name}.pf2"
+ {
+ FONTCONFIG_FILE = pkgs.makeFontsConf { fontDirectories = [ font.package ]; };
+ }
+ ''
+ # Use fontconfig to select the correct .ttf or .otf file based on name
+ font=$(
+ ${lib.getExe' pkgs.fontconfig "fc-match"} \
+ ${lib.escapeShellArg font.name} \
+ --format=%{file}
+ )
+
+ # Convert to .pf2
+ ${pkgs.grub2}/bin/grub-mkfont $font --output $out --size ${toString sizes.applications}
+ '';
+
+ inherit (config.stylix) imageScalingMode;
+
+ image-scale =
+ if imageScalingMode == "fill" then
+ "crop"
+ else if imageScalingMode == "fit" then
+ "fitheight"
+ else if imageScalingMode == "center" then
+ "padding"
+ # Grub doesn't seem to support tile
+ else
+ "crop";
+in
+{
+ options.stylix.targets.grub = {
+ enable = config.lib.stylix.mkEnableTarget "GRUB" true;
+
+ useImage = lib.mkOption {
+ description = "Whether to use your wallpaper image as the GRUB background.";
+ type = lib.types.bool;
+ default = false;
+ };
+ };
+
+ config.boot.loader.grub =
+ lib.mkIf (config.stylix.enable && config.stylix.targets.grub.enable)
+ {
+ backgroundColor = base00;
+ # Need to override the NixOS splash, this will match the background
+ splashImage = pixel "base00";
+
+ # This font will be used for the GRUB terminal
+ font = toString (mkGrubFont monospace);
+
+ # TODO: Include OS icons
+ theme =
+ pkgs.runCommand "stylix-grub"
+ {
+ themeTxt = ''
+ desktop-image: "background.png"
+ desktop-image-scale-method: "${image-scale}"
+ desktop-color: "${base00}"
+
+ title-text: ""
+
+ terminal-left: "10%"
+ terminal-top: "20%"
+ terminal-width: "80%"
+ terminal-height: "60%"
+
+ + progress_bar {
+ left = 25%
+ top = 80%+20 # 20 pixels below boot menu
+ width = 50%
+ height = 30
+
+ id = "__timeout__"
+ show_text = true
+ font = "${sansSerif.name}"
+ text = "@TIMEOUT_NOTIFICATION_MIDDLE@"
+
+ border_color = "${base00}"
+ bg_color = "${base00}"
+ fg_color = "${base0B}"
+ text_color = "${base05}"
+ }
+
+ + boot_menu {
+ left = 25%
+ top = 20%
+ width = 50%
+ height = 60%
+ menu_pixmap_style = "background_*.png"
+
+ item_height = 40
+ item_icon_space = 8
+ item_spacing = 0
+ item_padding = 0
+ item_font = "${sansSerif.name}"
+ item_color = "${base05}"
+
+ selected_item_color = "${base01}"
+ selected_item_pixmap_style = "selection_*.png"
+ }
+ '';
+ passAsFile = [ "themeTxt" ];
+ }
+ ''
+ mkdir $out
+ cp $themeTxtPath $out/theme.txt
+
+ ${
+ if
+ config.stylix.targets.grub.useImage
+ # Make sure the background image is .png by asking to convert it
+ then
+ "${pkgs.imagemagick}/bin/convert ${config.stylix.image} png32:$out/background.png"
+ else
+ "cp ${pixel "base00"} $out/background.png"
+ }
+
+ cp ${pixel "base01"} $out/background_c.png
+ cp ${pixel "base0B"} $out/selection_c.png
+
+ cp ${mkGrubFont sansSerif} $out/sans_serif.pf2
+ '';
+ };
+}
diff --git a/modules/gtk/gtk.mustache b/modules/gtk/gtk.mustache
new file mode 100644
index 0000000..d4ec694
--- /dev/null
+++ b/modules/gtk/gtk.mustache
@@ -0,0 +1,88 @@
+@define-color accent_color #{{base0D-hex}};
+@define-color accent_bg_color #{{base0D-hex}};
+@define-color accent_fg_color #{{base00-hex}};
+@define-color destructive_color #{{base08-hex}};
+@define-color destructive_bg_color #{{base08-hex}};
+@define-color destructive_fg_color #{{base00-hex}};
+@define-color success_color #{{base0B-hex}};
+@define-color success_bg_color #{{base0B-hex}};
+@define-color success_fg_color #{{base00-hex}};
+@define-color warning_color #{{base0E-hex}};
+@define-color warning_bg_color #{{base0E-hex}};
+@define-color warning_fg_color #{{base00-hex}};
+@define-color error_color #{{base08-hex}};
+@define-color error_bg_color #{{base08-hex}};
+@define-color error_fg_color #{{base00-hex}};
+@define-color window_bg_color #{{base00-hex}};
+@define-color window_fg_color #{{base05-hex}};
+@define-color view_bg_color #{{base00-hex}};
+@define-color view_fg_color #{{base05-hex}};
+@define-color headerbar_bg_color #{{base01-hex}};
+@define-color headerbar_fg_color #{{base05-hex}};
+@define-color headerbar_border_color rgba({{base01-dec-r}}, {{base01-dec-g}}, {{base01-dec-b}}, 0.7);
+@define-color headerbar_backdrop_color @window_bg_color;
+@define-color headerbar_shade_color rgba(0, 0, 0, 0.07);
+@define-color headerbar_darker_shade_color rgba(0, 0, 0, 0.07);
+@define-color sidebar_bg_color #{{base01-hex}};
+@define-color sidebar_fg_color #{{base05-hex}};
+@define-color sidebar_backdrop_color @window_bg_color;
+@define-color sidebar_shade_color rgba(0, 0, 0, 0.07);
+@define-color secondary_sidebar_bg_color @sidebar_bg_color;
+@define-color secondary_sidebar_fg_color @sidebar_fg_color;
+@define-color secondary_sidebar_backdrop_color @sidebar_backdrop_color;
+@define-color secondary_sidebar_shade_color @sidebar_shade_color;
+@define-color card_bg_color #{{base01-hex}};
+@define-color card_fg_color #{{base05-hex}};
+@define-color card_shade_color rgba(0, 0, 0, 0.07);
+@define-color dialog_bg_color #{{base01-hex}};
+@define-color dialog_fg_color #{{base05-hex}};
+@define-color popover_bg_color #{{base01-hex}};
+@define-color popover_fg_color #{{base05-hex}};
+@define-color popover_shade_color rgba(0, 0, 0, 0.07);
+@define-color shade_color rgba(0, 0, 0, 0.07);
+@define-color scrollbar_outline_color #{{base02-hex}};
+@define-color blue_1 #{{base0D-hex}};
+@define-color blue_2 #{{base0D-hex}};
+@define-color blue_3 #{{base0D-hex}};
+@define-color blue_4 #{{base0D-hex}};
+@define-color blue_5 #{{base0D-hex}};
+@define-color green_1 #{{base0B-hex}};
+@define-color green_2 #{{base0B-hex}};
+@define-color green_3 #{{base0B-hex}};
+@define-color green_4 #{{base0B-hex}};
+@define-color green_5 #{{base0B-hex}};
+@define-color yellow_1 #{{base0A-hex}};
+@define-color yellow_2 #{{base0A-hex}};
+@define-color yellow_3 #{{base0A-hex}};
+@define-color yellow_4 #{{base0A-hex}};
+@define-color yellow_5 #{{base0A-hex}};
+@define-color orange_1 #{{base09-hex}};
+@define-color orange_2 #{{base09-hex}};
+@define-color orange_3 #{{base09-hex}};
+@define-color orange_4 #{{base09-hex}};
+@define-color orange_5 #{{base09-hex}};
+@define-color red_1 #{{base08-hex}};
+@define-color red_2 #{{base08-hex}};
+@define-color red_3 #{{base08-hex}};
+@define-color red_4 #{{base08-hex}};
+@define-color red_5 #{{base08-hex}};
+@define-color purple_1 #{{base0E-hex}};
+@define-color purple_2 #{{base0E-hex}};
+@define-color purple_3 #{{base0E-hex}};
+@define-color purple_4 #{{base0E-hex}};
+@define-color purple_5 #{{base0E-hex}};
+@define-color brown_1 #{{base0F-hex}};
+@define-color brown_2 #{{base0F-hex}};
+@define-color brown_3 #{{base0F-hex}};
+@define-color brown_4 #{{base0F-hex}};
+@define-color brown_5 #{{base0F-hex}};
+@define-color light_1 #{{base01-hex}};
+@define-color light_2 #{{base01-hex}};
+@define-color light_3 #{{base01-hex}};
+@define-color light_4 #{{base01-hex}};
+@define-color light_5 #{{base01-hex}};
+@define-color dark_1 #{{base01-hex}};
+@define-color dark_2 #{{base01-hex}};
+@define-color dark_3 #{{base01-hex}};
+@define-color dark_4 #{{base01-hex}};
+@define-color dark_5 #{{base01-hex}};
diff --git a/modules/gtk/hm.nix b/modules/gtk/hm.nix
new file mode 100644
index 0000000..e3e8d59
--- /dev/null
+++ b/modules/gtk/hm.nix
@@ -0,0 +1,109 @@
+{
+ pkgs,
+ config,
+ lib,
+ options,
+ ...
+}:
+
+let
+ cfg = config.stylix.targets.gtk;
+
+ baseCss = config.lib.stylix.colors {
+ template = ./gtk.mustache;
+ extension = "css";
+ };
+
+ finalCss = pkgs.runCommandLocal "gtk.css" { } ''
+ cat ${baseCss} >>$out
+ echo ${lib.escapeShellArg cfg.extraCss} >>$out
+ '';
+in
+{
+ options.stylix.targets.gtk = {
+ enable = config.lib.stylix.mkEnableTarget "all GTK3, GTK4 and Libadwaita apps" true;
+
+ extraCss = lib.mkOption {
+ description = ''
+ Extra code added to `gtk-3.0/gtk.css` and `gtk-4.0/gtk.css`.
+ '';
+ type = lib.types.lines;
+ default = "";
+ example = ''
+ // Remove rounded corners
+ window.background { border-radius: 0; }
+ '';
+ };
+
+ flatpakSupport.enable = config.lib.stylix.mkEnableTarget "support for theming Flatpak apps" true;
+ };
+
+ config = lib.mkIf cfg.enable (
+ lib.mkMerge [
+ {
+ # programs.dconf.enable = true; required in system config
+ gtk = {
+ enable = true;
+ font = {
+ inherit (config.stylix.fonts.sansSerif) package name;
+ size = config.stylix.fonts.sizes.applications;
+ };
+ theme = {
+ package = pkgs.adw-gtk3;
+ name = "adw-gtk3";
+ };
+ };
+
+ xdg.configFile = {
+ "gtk-3.0/gtk.css".source = finalCss;
+ "gtk-4.0/gtk.css".source = finalCss;
+ };
+ }
+
+ (lib.mkIf cfg.flatpakSupport.enable (
+ lib.mkMerge [
+ {
+ # Flatpak apps apparently don't consume the CSS config. This workaround appends it to the theme directly.
+ home.file.".themes/${config.gtk.theme.name}".source =
+ pkgs.stdenvNoCC.mkDerivation
+ {
+ name = "flattenedGtkTheme";
+ src = "${config.gtk.theme.package}/share/themes/${config.gtk.theme.name}";
+
+ installPhase = ''
+ cp --recursive . $out
+ cat ${finalCss} | tee --append $out/gtk-{3,4}.0/gtk.css
+ '';
+ };
+ }
+ (
+ let
+ filesystem = "${config.home.homeDirectory}/.themes/${config.gtk.theme.name}:ro";
+ theme = config.gtk.theme.name;
+ in
+ if options ? services.flatpak.overrides then
+ {
+ # Let Flatpak apps read the theme and force them to use it.
+ # This requires nix-flatpak to be imported externally.
+ services.flatpak.overrides.global = {
+ Context.filesystems = [ filesystem ];
+ Environment.GTK_THEME = theme;
+ };
+ }
+ else
+ {
+ # This is likely incompatible with other modules that write to this file.
+ xdg.dataFile."flatpak/overrides/global".text = ''
+ [Context]
+ filesystems=${filesystem}
+
+ [Environment]
+ GTK_THEME=${theme}
+ '';
+ }
+ )
+ ]
+ ))
+ ]
+ );
+}
diff --git a/modules/gtk/nixos.nix b/modules/gtk/nixos.nix
new file mode 100644
index 0000000..3368857
--- /dev/null
+++ b/modules/gtk/nixos.nix
@@ -0,0 +1,11 @@
+{ config, lib, ... }:
+
+{
+ options.stylix.targets.gtk.enable =
+ config.lib.stylix.mkEnableTarget "all GTK3, GTK4 and Libadwaita apps" true;
+
+ config = lib.mkIf (config.stylix.enable && config.stylix.targets.gtk.enable) {
+ # Required for Home Manager's GTK settings to work
+ programs.dconf.enable = true;
+ };
+}
diff --git a/modules/helix/hm.nix b/modules/helix/hm.nix
new file mode 100644
index 0000000..5c137c6
--- /dev/null
+++ b/modules/helix/hm.nix
@@ -0,0 +1,38 @@
+{
+ pkgs,
+ config,
+ lib,
+ ...
+}:
+
+let
+ theme = config.lib.stylix.colors {
+ templateRepo = config.lib.stylix.templates.base16-helix;
+ };
+
+ # Removing the background exposes transparency from the terminal. The
+ # background might be helpful if the terminal isn't themed, so we only
+ # do this if transparency is actually enabled.
+ transparentTheme = pkgs.runCommandLocal "helix-transparent.toml" { } ''
+ sed 's/,\? bg = "base00"//g' <${theme} >$out
+ '';
+
+in
+{
+ options.stylix.targets.helix.enable =
+ config.lib.stylix.mkEnableTarget "Helix" true;
+
+ config =
+ lib.mkIf
+ (
+ config.stylix.enable
+ && config.stylix.targets.helix.enable
+ && config.programs.helix.enable
+ )
+ {
+ programs.helix.settings.theme = "stylix";
+
+ xdg.configFile."helix/themes/stylix.toml".source =
+ if config.stylix.opacity.terminal == 1.0 then theme else transparentTheme;
+ };
+}
diff --git a/modules/hyprland/hm.nix b/modules/hyprland/hm.nix
new file mode 100644
index 0000000..ad3e5c6
--- /dev/null
+++ b/modules/hyprland/hm.nix
@@ -0,0 +1,56 @@
+{ config, lib, ... }:
+
+{
+ options.stylix.targets.hyprland = {
+ enable = config.lib.stylix.mkEnableTarget "Hyprland" true;
+ hyprpaper.enable = config.lib.stylix.mkEnableTarget "Hyprpaper" true;
+ };
+
+ config =
+ let
+ cfg = config.stylix.targets.hyprland;
+ in
+ lib.mkIf
+ (
+ config.stylix.enable
+ && cfg.enable
+ && config.wayland.windowManager.hyprland.enable
+ )
+ (
+ lib.mkMerge [
+ {
+ wayland.windowManager.hyprland.settings =
+ let
+ inherit (config.lib.stylix) colors;
+
+ rgb = color: "rgb(${color})";
+ rgba = color: alpha: "rgba(${color}${alpha})";
+ in
+ {
+ decoration.shadow.color = rgba colors.base00 "99";
+ general = {
+ "col.active_border" = rgb colors.base0D;
+ "col.inactive_border" = rgb colors.base03;
+ };
+ group = {
+ "col.border_inactive" = rgb colors.base03;
+ "col.border_active" = rgb colors.base0D;
+ "col.border_locked_active" = rgb colors.base0C;
+
+ groupbar = {
+ text_color = rgb colors.base05;
+ "col.active" = rgb colors.base0D;
+ "col.inactive" = rgb colors.base03;
+ };
+ };
+ misc.background_color = rgb colors.base00;
+ };
+ }
+
+ (lib.mkIf cfg.hyprpaper.enable {
+ services.hyprpaper.enable = true;
+ stylix.targets.hyprpaper.enable = true;
+ })
+ ]
+ );
+}
diff --git a/modules/hyprland/testbed.nix b/modules/hyprland/testbed.nix
new file mode 100644
index 0000000..12ce63c
--- /dev/null
+++ b/modules/hyprland/testbed.nix
@@ -0,0 +1,17 @@
+{ lib, pkgs, ... }:
+
+{
+ environment.loginShellInit = lib.getExe pkgs.hyprland;
+ programs.hyprland.enable = true;
+
+ home-manager.sharedModules = [
+ {
+ wayland.windowManager.hyprland = {
+ enable = true;
+
+ # We need something to open a window so that we can check the window borders
+ settings.bind = [ "ALT, RETURN, exec, ${lib.getExe pkgs.foot}" ];
+ };
+ }
+ ];
+}
diff --git a/modules/hyprlock/hm.nix b/modules/hyprlock/hm.nix
new file mode 100644
index 0000000..e3acef9
--- /dev/null
+++ b/modules/hyprlock/hm.nix
@@ -0,0 +1,21 @@
+{ config, lib, ... }:
+
+with config.lib.stylix;
+{
+ options.stylix.targets.hyprlock.enable = mkEnableTarget "Hyprlock" true;
+
+ config =
+ lib.mkIf (config.stylix.enable && config.stylix.targets.hyprlock.enable)
+ {
+ programs.hyprlock.settings = {
+ background.path = "${config.stylix.image}";
+ input-field = with colors; {
+ outer_color = "rgb(${base03})";
+ inner_color = "rgb(${base00})";
+ font_color = "rgb(${base05})";
+ fail_color = "rgb(${base08})";
+ check_color = "rgb(${base0A})";
+ };
+ };
+ };
+}
diff --git a/modules/hyprpaper/hm.nix b/modules/hyprpaper/hm.nix
new file mode 100644
index 0000000..325f050
--- /dev/null
+++ b/modules/hyprpaper/hm.nix
@@ -0,0 +1,14 @@
+{ config, lib, ... }:
+{
+ options.stylix.targets.hyprpaper.enable =
+ config.lib.stylix.mkEnableTarget "Hyprpaper" true;
+
+ config =
+ lib.mkIf (config.stylix.enable && config.stylix.targets.hyprpaper.enable)
+ {
+ services.hyprpaper.settings = {
+ preload = [ "${config.stylix.image}" ];
+ wallpaper = [ ",${config.stylix.image}" ];
+ };
+ };
+}
diff --git a/modules/i3/hm.nix b/modules/i3/hm.nix
new file mode 100644
index 0000000..794c8cd
--- /dev/null
+++ b/modules/i3/hm.nix
@@ -0,0 +1,104 @@
+{ config, lib, ... }:
+
+with config.lib.stylix.colors.withHashtag;
+
+let
+ text = base05;
+ urgent = base08;
+ focused = base0D;
+ unfocused = base03;
+
+ fonts =
+ let
+ inherit (config.stylix) fonts;
+ in
+ {
+ names = [ fonts.sansSerif.name ];
+ size = fonts.sizes.desktop * 1.0;
+ };
+
+in
+{
+ options.stylix.targets.i3.enable = config.lib.stylix.mkEnableTarget "i3" true;
+
+ config = lib.mkMerge [
+ (lib.mkIf config.stylix.targets.i3.enable {
+ xsession.windowManager.i3.config = {
+ inherit fonts;
+
+ colors =
+ let
+ background = base00;
+ indicator = base0B;
+ in
+ {
+ inherit background;
+ urgent = {
+ inherit background indicator text;
+ border = urgent;
+ childBorder = urgent;
+ };
+ focused = {
+ inherit background indicator text;
+ border = focused;
+ childBorder = focused;
+ };
+ focusedInactive = {
+ inherit background indicator text;
+ border = unfocused;
+ childBorder = unfocused;
+ };
+ unfocused = {
+ inherit background indicator text;
+ border = unfocused;
+ childBorder = unfocused;
+ };
+ placeholder = {
+ inherit background indicator text;
+ border = unfocused;
+ childBorder = unfocused;
+ };
+ };
+
+ # output."*".bg = "${config.stylix.image} fill";
+ };
+ })
+
+ {
+ # Merge this with your bar configuration using //config.lib.stylix.i3.bar
+ lib.stylix.i3.bar = {
+ inherit fonts;
+
+ colors =
+ let
+ background = base00;
+ border = background;
+ in
+ {
+ inherit background;
+ statusline = text;
+ separator = base03;
+ focusedWorkspace = {
+ inherit text background;
+ border = focused;
+ };
+ activeWorkspace = {
+ inherit border background;
+ text = focused;
+ };
+ inactiveWorkspace = {
+ inherit text border background;
+ };
+ urgentWorkspace = {
+ inherit text background;
+ border = urgent;
+ };
+ bindingMode = {
+ inherit text border;
+ background = urgent;
+ };
+ };
+ };
+ }
+ ];
+}
diff --git a/modules/i3status-rust/hm.nix b/modules/i3status-rust/hm.nix
new file mode 100644
index 0000000..47fbd72
--- /dev/null
+++ b/modules/i3status-rust/hm.nix
@@ -0,0 +1,22 @@
+{ config, lib, ... }:
+
+let
+ colors = config.lib.stylix.colors.withHashtag;
+in
+{
+ # Merge this with your bar's theme's overrides with //config.lib.stylix.i3status-rust.bar
+ config.lib.stylix.i3status-rust.bar = with colors; {
+ idle_bg = base00;
+ idle_fg = base05;
+ info_bg = base09;
+ info_fg = base00;
+ good_bg = base01;
+ good_fg = base05;
+ warning_bg = base0A;
+ warning_fg = base00;
+ critical_bg = base08;
+ critical_fg = base00;
+ separator_bg = base00;
+ separator_fg = base05;
+ };
+}
diff --git a/modules/k9s/hm.nix b/modules/k9s/hm.nix
new file mode 100644
index 0000000..0706ce3
--- /dev/null
+++ b/modules/k9s/hm.nix
@@ -0,0 +1,131 @@
+{ config, lib, ... }:
+
+with config.lib.stylix.colors.withHashtag;
+
+{
+ options.stylix.targets.k9s.enable = config.lib.stylix.mkEnableTarget "k9s" true;
+
+ config = lib.mkIf config.stylix.targets.k9s.enable {
+ programs.k9s.skins.skin = {
+ k9s = {
+ body = {
+ fgColor = base05-hex;
+ bgColor = "default";
+ logoColor = base0C-hex;
+ };
+
+ prompt = {
+ fgColor = base05-hex;
+ bgColor = base00-hex;
+ suggestColor = base0A-hex;
+ };
+
+ info = {
+ fgColor = base0B-hex;
+ sectionColor = base05-hex;
+ };
+
+ dialog = {
+ fgColor = base05-hex;
+ bgColor = "default";
+ buttonFgColor = base05-hex;
+ buttonBgColor = base0C-hex;
+ buttonFocusFgColor = base0E-hex;
+ buttonFocusBgColor = base0B-hex;
+ labelFgColor = base0A-hex;
+ fieldFgColor = base05-hex;
+ };
+
+ frame = {
+ border = {
+ fgColor = base02-hex;
+ focusColor = base01-hex;
+ };
+
+ menu = {
+ fgColor = base05-hex;
+ keyColor = base0B-hex;
+ numKeyColor = base0B-hex;
+ };
+
+ crumbs = {
+ fgColor = base05-hex;
+ bgColor = base01-hex;
+ activeColor = base01-hex;
+ };
+
+ status = {
+ newColor = base08-hex;
+ modifyColor = base0C-hex;
+ addColor = base09-hex;
+ errorColor = base0D-hex;
+ highlightcolor = base0A-hex;
+ killColor = base03-hex;
+ completedColor = base03-hex;
+ };
+
+ title = {
+ fgColor = base05-hex;
+ bgColor = base01-hex;
+ highlightColor = base0A-hex;
+ counterColor = base0C-hex;
+ filterColor = base0B-hex;
+ };
+ };
+
+ views = {
+ charts = {
+ bgColor = "default";
+ defaultDialColors = [
+ base0C-hex
+ base0D-hex
+ ];
+ defaultChartColors = [
+ base0C-hex
+ base0D-hex
+ ];
+ };
+
+ table = {
+ fgColor = base05-hex;
+ bgColor = "default";
+ header = {
+ fgColor = base05-hex;
+ bgColor = "default";
+ sorterColor = base08-hex;
+ };
+ };
+
+ xray = {
+ fgColor = base05-hex;
+ bgColor = "default";
+ cursorColor = base01-hex;
+ graphicColor = base0C-hex;
+ showIcons = false;
+ };
+
+ yaml = {
+ keyColor = base0B-hex;
+ colonColor = base0C-hex;
+ valueColor = base05-hex;
+ };
+
+ logs = {
+ fgColor = base05-hex;
+ bgColor = "default";
+ indicator = {
+ fgColor = base05-hex;
+ bgColor = base0C-hex;
+ };
+ };
+
+ help = {
+ fgColor = base05-hex;
+ bgColor = base00-hex;
+ indicator.fgColor = base0D-hex;
+ };
+ };
+ };
+ };
+ };
+}
diff --git a/modules/kde/hm.nix b/modules/kde/hm.nix
new file mode 100644
index 0000000..f1db5d8
--- /dev/null
+++ b/modules/kde/hm.nix
@@ -0,0 +1,314 @@
+{
+ pkgs,
+ config,
+ lib,
+ ...
+}:
+
+with config.stylix.fonts;
+with config.lib.stylix.colors;
+
+let
+ cfg = config.stylix.targets.kde;
+
+ formatValue =
+ value:
+ if builtins.isBool value then
+ if value then "true" else "false"
+ else
+ builtins.toString value;
+
+ formatSection =
+ path: data:
+ let
+ header = lib.concatStrings (map (p: "[${p}]") path);
+ formatChild = name: formatLines (path ++ [ name ]);
+ children = lib.mapAttrsToList formatChild data;
+ partitioned = lib.partition builtins.isString children;
+ directChildren = partitioned.right;
+ indirectChildren = partitioned.wrong;
+ in
+ lib.optional (directChildren != [ ]) header
+ ++ directChildren
+ ++ lib.flatten indirectChildren;
+
+ formatLines =
+ path: data:
+ if builtins.isAttrs data then
+ if data ? _immutable then
+ if builtins.isAttrs data.value then
+ formatSection (path ++ [ "$i" ]) data.value
+ else
+ "${lib.last path}[$i]=${formatValue data.value}"
+ else
+ formatSection path data
+ else
+ "${lib.last path}=${formatValue data}";
+
+ formatConfig = data: lib.concatStringsSep "\n" (formatLines [ ] data);
+
+ # Marking a setting as immutable should prevent it being overwritten
+ # through the system settings menu.
+ makeImmutable = value: {
+ _immutable = true;
+ inherit value;
+ };
+
+ # PascalCase is the standard naming for color scheme files. Schemes named
+ # in kebab-case will load when selected manually, but don't work with a
+ # look and feel package.
+ colorschemeSlug = lib.concatStrings (
+ builtins.filter builtins.isString (builtins.split "[^a-zA-Z]" scheme)
+ );
+
+ colorEffect = {
+ ColorEffect = 0;
+ ColorAmount = 0;
+ ContrastEffect = 1;
+ ContrastAmount = 0.5;
+ IntensityEffect = 0;
+ IntensityAmount = 0;
+ };
+
+ colors = {
+ BackgroundNormal = "${base00-rgb-r},${base00-rgb-g},${base00-rgb-b}";
+ BackgroundAlternate = "${base01-rgb-r},${base01-rgb-g},${base01-rgb-b}";
+ DecorationFocus = "${base0D-rgb-r},${base0D-rgb-g},${base0D-rgb-b}";
+ DecorationHover = "${base0D-rgb-r},${base0D-rgb-g},${base0D-rgb-b}";
+ ForegroundNormal = "${base05-rgb-r},${base05-rgb-g},${base05-rgb-b}";
+ ForegroundActive = "${base05-rgb-r},${base05-rgb-g},${base05-rgb-b}";
+ ForegroundInactive = "${base05-rgb-r},${base05-rgb-g},${base05-rgb-b}";
+ ForegroundLink = "${base05-rgb-r},${base05-rgb-g},${base05-rgb-b}";
+ ForegroundVisited = "${base05-rgb-r},${base05-rgb-g},${base05-rgb-b}";
+ ForegroundNegative = "${base08-rgb-r},${base08-rgb-g},${base08-rgb-b}";
+ ForegroundNeutral = "${base0D-rgb-r},${base0D-rgb-g},${base0D-rgb-b}";
+ ForegroundPositive = "${base0B-rgb-r},${base0B-rgb-g},${base0B-rgb-b}";
+ };
+
+ colorscheme = {
+ General = {
+ ColorScheme = colorschemeSlug;
+ Name = scheme;
+ };
+
+ "ColorEffects:Disabled" = colorEffect;
+ "ColorEffects:Inactive" = colorEffect;
+
+ "Colors:Window" = colors;
+ "Colors:View" = colors;
+ "Colors:Button" = colors;
+ "Colors:Tooltip" = colors;
+ "Colors:Complementary" = colors;
+ "Colors:Selection" = colors // {
+ BackgroundNormal = "${base0D-rgb-r},${base0D-rgb-g},${base0D-rgb-b}";
+ BackgroundAlternate = "${base0D-rgb-r},${base0D-rgb-g},${base0D-rgb-b}";
+ ForegroundNormal = "${base00-rgb-r},${base00-rgb-g},${base00-rgb-b}";
+ ForegroundActive = "${base00-rgb-r},${base00-rgb-g},${base00-rgb-b}";
+ ForegroundInactive = "${base00-rgb-r},${base00-rgb-g},${base00-rgb-b}";
+ ForegroundLink = "${base00-rgb-r},${base00-rgb-g},${base00-rgb-b}";
+ ForegroundVisited = "${base00-rgb-r},${base00-rgb-g},${base00-rgb-b}";
+ };
+
+ WM = {
+ activeBlend = "${base0A-rgb-r},${base0A-rgb-g},${base0A-rgb-b}";
+ activeBackground = "${base00-rgb-r},${base00-rgb-g},${base00-rgb-b}";
+ activeForeground = "${base05-rgb-r},${base05-rgb-g},${base05-rgb-b}";
+ inactiveBlend = "${base03-rgb-r},${base03-rgb-g},${base03-rgb-b}";
+ inactiveBackground = "${base00-rgb-r},${base00-rgb-g},${base00-rgb-b}";
+ inactiveForeground = "${base05-rgb-r},${base05-rgb-g},${base05-rgb-b}";
+ };
+ };
+
+ wallpaperMetadata = {
+ KPlugin = {
+ Id = "stylix";
+ Name = "Stylix";
+ };
+ };
+
+ lookAndFeelMetadata = {
+ KPlugin = {
+ Id = "stylix";
+ Name = "Stylix";
+ Description = "Generated from your Home Manager configuration";
+ ServiceTypes = [ "Plasma/LookAndFeel" ];
+ Website = "https://github.com/danth/stylix";
+ };
+ KPackageStructure = "Plasma/LookAndFeel";
+ };
+
+ lookAndFeelDefaults = {
+ kwinrc."org.kde.kdecoration2".library = "org.kde.breeze";
+ plasmarc.Theme.name = "default";
+
+ kdeglobals = {
+ KDE.widgetStyle = "Breeze";
+ General.ColorScheme = colorschemeSlug;
+ };
+
+ # This only takes effect on the first login.
+ Wallpaper.Image = "stylix";
+ };
+
+ # Contains a wallpaper package, a colorscheme file, and a look and feel
+ # package which depends on both.
+ themePackage =
+ pkgs.runCommandLocal "stylix-kde-theme"
+ {
+ colorscheme = formatConfig colorscheme;
+ wallpaperMetadata = builtins.toJSON wallpaperMetadata;
+ wallpaperImage = config.stylix.image;
+ lookAndFeelMetadata = builtins.toJSON lookAndFeelMetadata;
+ lookAndFeelDefaults = formatConfig lookAndFeelDefaults;
+ }
+ ''
+ write_text() {
+ mkdir --parents "$(dirname "$2")"
+ printf '%s\n' "$1" >"$2"
+ }
+
+ PATH="${pkgs.imagemagick}/bin:$PATH"
+
+ wallpaper="$out/share/wallpapers/stylix"
+ look_and_feel="$out/share/plasma/look-and-feel/stylix"
+
+ mkdir --parents "$wallpaper/contents/images"
+
+ magick \
+ "$wallpaperImage" \
+ -thumbnail 400x250 \
+ "$wallpaper/contents/screenshot.png"
+
+ dimensions="$(identify -ping -format '%wx%h' "$wallpaperImage")"
+ magick "$wallpaperImage" "$wallpaper/contents/images/$dimensions.png"
+
+ write_text \
+ "$colorscheme" \
+ "$out/share/color-schemes/${colorschemeSlug}.colors"
+
+ write_text "$wallpaperMetadata" "$wallpaper/metadata.json"
+ write_text "$lookAndFeelMetadata" "$look_and_feel/metadata.json"
+ write_text "$lookAndFeelDefaults" "$look_and_feel/contents/defaults"
+ '';
+
+ # The cursor theme can be configured through a look and feel package,
+ # however its size cannot.
+ kcminputrc = {
+ Mouse = {
+ cursorSize = makeImmutable (toString config.stylix.cursor.size);
+ cursorTheme = makeImmutable config.stylix.cursor.name;
+ };
+ };
+
+ kded5rc = {
+ # The gtkconfig module copies settings from KDE to the GTK configuration.
+ # This blocks Home Manager activation because the same files are already
+ # managed by Stylix.
+ Module-gtkconfig = makeImmutable {
+ autoload = false;
+ };
+ };
+
+ kdeglobals = {
+ KDE.LookAndFeelPackage = makeImmutable "stylix";
+
+ General = rec {
+ font = makeImmutable "${sansSerif.name},${toString sizes.applications},-1,5,50,0,0,0,0,0";
+ fixed = makeImmutable "${monospace.name},${toString sizes.terminal},-1,5,50,0,0,0,0,0";
+ desktopFont = makeImmutable "${sansSerif.name},${toString sizes.desktop},-1,5,50,0,0,0,0,0";
+ menuFont = desktopFont;
+ taskbarFont = desktopFont;
+ toolBarFont = desktopFont;
+ smallestReadableFont = desktopFont;
+ };
+ };
+
+ configPackage =
+ pkgs.runCommandLocal "stylix-kde-config"
+ {
+ kcminputrc = formatConfig kcminputrc;
+ kded5rc = formatConfig kded5rc;
+ kdeglobals = formatConfig kdeglobals;
+ }
+ ''
+ mkdir "$out"
+
+ printf '%s\n' "$kcminputrc" >"$out/kcminputrc"
+ printf '%s\n' "$kded5rc" >"$out/kded5rc"
+ printf '%s\n' "$kdeglobals" >"$out/kdeglobals"
+ '';
+
+ # plasma-apply-wallpaperimage is necessary to change the wallpaper
+ # after the first login.
+ #
+ # plasma-apply-lookandfeel is only here to trigger a hot reload, the theme
+ # would still be applied without it if you logged out and back in.
+ #
+ # Home Manager clears $PATH before running the activation script, but we
+ # want to avoid installing these tools explicitly because that would pull
+ # in large dependencies for people who aren't actually using KDE.
+ # The workaround used is to assume a list of common paths where the tools
+ # might be installed, and look there. The ideal solution would require
+ # changes to KDE to make it possible to update the wallpaper through
+ # config files alone.
+ activator = pkgs.writeShellScriptBin "stylix-set-kde-wallpaper" ''
+ set -eu
+ global_path() {
+ for directory in /run/current-system/sw/bin /usr/bin /bin; do
+ if [[ -f "$directory/$1" ]]; then
+ printf '%s\n' "$directory/$1"
+ return 0
+ fi
+ done
+
+ return 1
+ }
+
+ if wallpaper_image="$(global_path plasma-apply-wallpaperimage)"; then
+ "$wallpaper_image" "${themePackage}/share/wallpapers/stylix"
+ else
+ echo "Skipping plasma-apply-wallpaperimage: command not found"
+ fi
+
+ if look_and_feel="$(global_path plasma-apply-lookandfeel)"; then
+ "$look_and_feel" --apply stylix
+ else
+ echo "Skipping plasma-apply-lookandfeel: command not found"
+ fi
+ '';
+
+ activateDocs = "https://stylix.danth.me/options/hm.html#stylixtargetskdeservice";
+in
+{
+ options.stylix.targets.kde.enable = config.lib.stylix.mkEnableTarget "KDE" true;
+
+ config =
+ lib.mkIf
+ (config.stylix.enable && cfg.enable && pkgs.stdenv.hostPlatform.isLinux)
+ {
+ home = {
+ packages = [ themePackage ];
+
+ # This activation entry will run the theme activator when the homeConfiguration is activated
+ # Note: This only works in an already running Plasma session.
+ activation.stylixLookAndFeel = lib.hm.dag.entryAfter [ "writeBoundary" ] ''
+ ${lib.getExe activator} || verboseEcho \
+ "KDE theme setting failed. See `${activateDocs}`"
+ '';
+ };
+
+ xdg = {
+ systemDirs.config = [ "${configPackage}" ];
+
+ # This desktop entry will run the theme activator when a new Plasma session is started
+ # Note: This doesn't run again if a new homeConfiguration is activated from a running Plasma session
+ configFile."autostart/stylix-activator.desktop".text = ''
+ [Desktop Entry]
+ Type=Application
+ Exec=${lib.getExe activator}
+ Name=Stylix Activator
+ X-KDE-AutostartScript=true
+ '';
+ };
+ };
+}
diff --git a/modules/kde/testbed.nix b/modules/kde/testbed.nix
new file mode 100644
index 0000000..07afbc8
--- /dev/null
+++ b/modules/kde/testbed.nix
@@ -0,0 +1,10 @@
+{
+ services = {
+ displayManager.sddm.enable = true;
+
+ xserver = {
+ enable = true;
+ desktopManager.plasma5.enable = true;
+ };
+ };
+}
diff --git a/modules/kitty/hm.nix b/modules/kitty/hm.nix
new file mode 100644
index 0000000..b63da52
--- /dev/null
+++ b/modules/kitty/hm.nix
@@ -0,0 +1,38 @@
+{ config, lib, ... }:
+
+let
+ cfg = config.stylix.targets.kitty;
+ theme = config.lib.stylix.colors {
+ templateRepo = config.lib.stylix.templates.tinted-kitty;
+ target = if cfg.variant256Colors then "default-256" else "default";
+ };
+in
+{
+ options.stylix.targets.kitty = {
+ enable = config.lib.stylix.mkEnableTarget "Kitty" true;
+
+ variant256Colors = lib.mkOption {
+ description = ''
+ Whether to use the [256-color variant](https://github.com/kdrag0n/base16-kitty#256-color-variants)
+ rather than the default combination of colors.
+ '';
+ type = lib.types.bool;
+ default = false;
+ };
+ };
+
+ config = lib.mkIf cfg.enable {
+ programs.kitty = {
+ font = {
+ inherit (config.stylix.fonts.monospace) package name;
+ size = config.stylix.fonts.sizes.terminal;
+ };
+ settings.background_opacity =
+ with config.stylix.opacity;
+ "${builtins.toString terminal}";
+ extraConfig = ''
+ include ${theme}
+ '';
+ };
+ };
+}
diff --git a/modules/kitty/testbed.nix b/modules/kitty/testbed.nix
new file mode 100644
index 0000000..3f61076
--- /dev/null
+++ b/modules/kitty/testbed.nix
@@ -0,0 +1,22 @@
+{ pkgs, ... }:
+
+let
+ package = pkgs.kitty;
+
+in
+{
+ stylix.testbed.application = {
+ enable = true;
+ name = "kitty";
+ inherit package;
+ };
+
+ home-manager.sharedModules = [
+ {
+ programs.kitty = {
+ enable = true;
+ inherit package;
+ };
+ }
+ ];
+}
diff --git a/modules/kmscon/nixos.nix b/modules/kmscon/nixos.nix
new file mode 100644
index 0000000..c9ab88c
--- /dev/null
+++ b/modules/kmscon/nixos.nix
@@ -0,0 +1,45 @@
+{ config, lib, ... }:
+{
+ options.stylix.targets.kmscon.enable =
+ config.lib.stylix.mkEnableTarget "the kmscon virtual console" true;
+
+ config.services.kmscon =
+ lib.mkIf (config.stylix.enable && config.stylix.targets.kmscon.enable)
+ {
+ fonts = [ config.stylix.fonts.monospace ];
+ extraConfig =
+ let
+ formatBase =
+ name:
+ let
+ getComponent = comp: config.lib.stylix.colors."${name}-rgb-${comp}";
+ in
+ "${getComponent "r"},${getComponent "g"},${getComponent "b"}";
+ in
+ ''
+ font-size=${builtins.toString config.stylix.fonts.sizes.terminal}
+
+ palette=custom
+
+ palette-black=${formatBase "base00"}
+ palette-red=${formatBase "base08"}
+ palette-green=${formatBase "base0B"}
+ palette-yellow=${formatBase "base0A"}
+ palette-blue=${formatBase "base0D"}
+ palette-magenta=${formatBase "base0E"}
+ palette-cyan=${formatBase "base0C"}
+ palette-light-grey=${formatBase "base05"}
+ palette-dark-grey=${formatBase "base03"}
+ palette-light-red=${formatBase "base08"}
+ palette-light-green=${formatBase "base0B"}
+ palette-light-yellow=${formatBase "base0A"}
+ palette-light-blue=${formatBase "base0D"}
+ palette-light-magenta=${formatBase "base0E"}
+ palette-light-cyan=${formatBase "base0C"}
+ palette-white=${formatBase "base07"}
+
+ palette-background=${formatBase "base00"}
+ palette-foreground=${formatBase "base05"}
+ '';
+ };
+}
diff --git a/modules/kubecolor/hm.nix b/modules/kubecolor/hm.nix
new file mode 100644
index 0000000..942eee0
--- /dev/null
+++ b/modules/kubecolor/hm.nix
@@ -0,0 +1,74 @@
+{ config, lib, ... }:
+{
+ options.stylix.targets.kubecolor.enable =
+ config.lib.stylix.mkEnableTarget "kubecolor" true;
+
+ config = lib.mkIf config.stylix.targets.kubecolor.enable {
+ programs.kubecolor.settings = {
+ preset =
+ if config.stylix.polarity == "either" then "" else "${config.stylix.polarity}";
+ theme = {
+ base = {
+ info = "fg=${config.lib.stylix.colors.withHashtag.base05-hex}";
+ primary = "fg=${config.lib.stylix.colors.withHashtag.base0E-hex}";
+ secondary = "fg=${config.lib.stylix.colors.withHashtag.base0D-hex}";
+ success = "fg=${config.lib.stylix.colors.withHashtag.base0B-hex}:bold";
+ warning = "fg=${config.lib.stylix.colors.withHashtag.base0A-hex}:bold";
+ danger = "fg=${config.lib.stylix.colors.withHashtag.base08-hex}:bold";
+ muted = "fg=${config.lib.stylix.colors.withHashtag.base04-hex}";
+ key = "fg=${config.lib.stylix.colors.withHashtag.base07-hex}:bold";
+ };
+ default = "fg=${config.lib.stylix.colors.withHashtag.base05-hex}";
+ data = {
+ key = "fg=${config.lib.stylix.colors.withHashtag.base07-hex}:bold";
+ string = "fg=${config.lib.stylix.colors.withHashtag.base05-hex}";
+ true = "fg=${config.lib.stylix.colors.withHashtag.base0B-hex}:bold";
+ false = "fg=${config.lib.stylix.colors.withHashtag.base08-hex}:bold";
+ number = "fg=${config.lib.stylix.colors.withHashtag.base0E-hex}";
+ null = "fg=${config.lib.stylix.colors.withHashtag.base04-hex}";
+ quantity = "fg=${config.lib.stylix.colors.withHashtag.base0E-hex}";
+ duration = "fg=${config.lib.stylix.colors.withHashtag.base09-hex}";
+ durationfresh = "fg=${config.lib.stylix.colors.withHashtag.base0B-hex}";
+ ratio = {
+ zero = "fg=${config.lib.stylix.colors.withHashtag.base04-hex}";
+ equal = "fg=${config.lib.stylix.colors.withHashtag.base0B-hex}";
+ unequal = "fg=${config.lib.stylix.colors.withHashtag.base0A-hex}";
+ };
+ };
+ status = {
+ success = "fg=${config.lib.stylix.colors.withHashtag.base0B-hex}:bold";
+ warning = "fg=${config.lib.stylix.colors.withHashtag.base0A-hex}:bold";
+ error = "fg=${config.lib.stylix.colors.withHashtag.base08-hex}:bold";
+ };
+ table = {
+ header = "fg=${config.lib.stylix.colors.withHashtag.base05-hex}:bold";
+ columns = "fg=${config.lib.stylix.colors.withHashtag.base05-hex}";
+ };
+ stderr = {
+ default = "fg=${config.lib.stylix.colors.withHashtag.base05-hex}";
+ error = "fg=${config.lib.stylix.colors.withHashtag.base08-hex}:bold";
+ };
+ describe = {
+ key = "fg=${config.lib.stylix.colors.withHashtag.base07-hex}:bold";
+ };
+ apply = {
+ created = "fg=${config.lib.stylix.colors.withHashtag.base0B-hex}";
+ configured = "fg=${config.lib.stylix.colors.withHashtag.base0A-hex}";
+ unchanged = "fg=${config.lib.stylix.colors.withHashtag.base05-hex}";
+ dryrun = "fg=${config.lib.stylix.colors.withHashtag.base0D-hex}";
+ fallback = "fg=${config.lib.stylix.colors.withHashtag.base05-hex}";
+ };
+ explain = {
+ key = "fg=${config.lib.stylix.colors.withHashtag.base07-hex}:bold";
+ required = "fg=${config.lib.stylix.colors.withHashtag.base00-hex}:bold";
+ };
+ options = {
+ flag = "fg=${config.lib.stylix.colors.withHashtag.base07-hex}:bold";
+ };
+ version = {
+ key = "fg=${config.lib.stylix.colors.withHashtag.base07-hex}:bold";
+ };
+ };
+ };
+ };
+}
diff --git a/modules/lazygit/hm.nix b/modules/lazygit/hm.nix
new file mode 100644
index 0000000..59f6a0b
--- /dev/null
+++ b/modules/lazygit/hm.nix
@@ -0,0 +1,34 @@
+{
+ config,
+ lib,
+ ...
+}:
+let
+ colors = config.lib.stylix.colors.withHashtag;
+in
+{
+ options.stylix.targets.lazygit.enable =
+ config.lib.stylix.mkEnableTarget "lazygit" true;
+
+ config =
+ lib.mkIf (config.stylix.enable && config.stylix.targets.lazygit.enable)
+ {
+ programs.lazygit.settings.gui.theme = {
+ activeBorderColor = [
+ colors.base07
+ "bold"
+ ];
+ inactiveBorderColor = [ colors.base04 ];
+ searchingActiveBorderColor = [
+ colors.base02
+ "bold"
+ ];
+ optionsTextColor = [ colors.base06 ];
+ selectedLineBgColor = [ colors.base03 ];
+ cherryPickedCommitBgColor = [ colors.base02 ];
+ cherryPickedCommitFgColor = [ colors.base03 ];
+ unstagedChangesColor = [ colors.base08 ];
+ defaultFgColor = [ colors.base05 ];
+ };
+ };
+}
diff --git a/modules/lightdm/nixos.nix b/modules/lightdm/nixos.nix
new file mode 100644
index 0000000..3687358
--- /dev/null
+++ b/modules/lightdm/nixos.nix
@@ -0,0 +1,10 @@
+{ config, lib, ... }:
+
+{
+ options.stylix.targets.lightdm.enable =
+ config.lib.stylix.mkEnableTarget "LightDM" true;
+
+ config.services.xserver.displayManager.lightdm.background = lib.mkIf (
+ config.stylix.enable && config.stylix.targets.lightdm.enable
+ ) config.stylix.image;
+}
diff --git a/modules/mako/hm.nix b/modules/mako/hm.nix
new file mode 100644
index 0000000..2acbe1f
--- /dev/null
+++ b/modules/mako/hm.nix
@@ -0,0 +1,43 @@
+{
+ config,
+ lib,
+ options,
+ ...
+}:
+
+with config.lib.stylix.colors.withHashtag;
+with config.stylix.fonts;
+let
+ makoOpacity = lib.toHexString (
+ ((builtins.ceil (config.stylix.opacity.popups * 100)) * 255) / 100
+ );
+in
+{
+ options.stylix.targets.mako.enable =
+ config.lib.stylix.mkEnableTarget "Mako" true;
+
+ # Referenced https://github.com/stacyharper/base16-mako
+ config = lib.optionalAttrs (options.services ? mako) (
+ lib.mkIf (config.stylix.enable && config.stylix.targets.mako.enable) {
+ services.mako = {
+ backgroundColor = base00 + makoOpacity;
+ borderColor = base0D;
+ textColor = base05;
+ progressColor = "over ${base02}";
+ font = "${sansSerif.name} ${toString sizes.popups}";
+ # I wish the mako hm module was like the dunst one
+ extraConfig = ''
+ [urgency=low]
+ background-color=${base00}${makoOpacity}
+ border-color=${base0D}
+ text-color=${base0A}
+
+ [urgency=high]
+ background-color=${base00}${makoOpacity}
+ border-color=${base0D}
+ text-color=${base08}
+ '';
+ };
+ }
+ );
+}
diff --git a/modules/mangohud/hm.nix b/modules/mangohud/hm.nix
new file mode 100644
index 0000000..53ee288
--- /dev/null
+++ b/modules/mangohud/hm.nix
@@ -0,0 +1,41 @@
+{ config, lib, ... }:
+
+let
+ inherit (config.stylix) fonts opacity;
+ inherit (config.lib.stylix) colors;
+in
+{
+ options.stylix.targets.mangohud.enable =
+ config.lib.stylix.mkEnableTarget "mangohud" true;
+
+ config =
+ lib.mkIf (config.stylix.enable && config.stylix.targets.mangohud.enable)
+ {
+ programs.mangohud.settings = with colors; {
+ font_size = fonts.sizes.applications;
+ font_size_text = fonts.sizes.applications;
+ background_alpha = opacity.popups;
+ alpha = opacity.applications;
+ text_color = base05;
+ text_outline_color = base00;
+ background_color = base00;
+ gpu_color = base0B;
+ cpu_color = base0D;
+ vram_color = base0C;
+ media_player_color = base05;
+ engine_color = base0E;
+ wine_color = base0E;
+ frametime_color = base0B;
+ battery_color = base04;
+ io_color = base0A;
+ gpu_load_color = "${base0B}, ${base0A}, ${base08}";
+ cpu_load_color = "${base0B}, ${base0A}, ${base08}";
+ fps_color = "${base0B}, ${base0A}, ${base08}";
+
+ # TODO: Use the point unit:
+ # https://github.com/danth/stylix/issues/251.
+ font_scale = 1.33333;
+ };
+ };
+
+}
diff --git a/modules/micro/hm.nix b/modules/micro/hm.nix
new file mode 100644
index 0000000..540f4ab
--- /dev/null
+++ b/modules/micro/hm.nix
@@ -0,0 +1,16 @@
+{
+ config,
+ lib,
+ ...
+}:
+{
+ options.stylix.targets.micro.enable =
+ config.lib.stylix.mkEnableTarget "micro" true;
+
+ config = lib.mkIf (config.stylix.enable && config.stylix.targets.micro.enable) {
+ # TODO: Provide a real colorscheme once [1] is resolved.
+ #
+ # [1]: https://github.com/danth/stylix/issues/249
+ programs.micro.settings.colorscheme = "simple";
+ };
+}
diff --git a/modules/ncspot/hm.nix b/modules/ncspot/hm.nix
new file mode 100644
index 0000000..592dc2f
--- /dev/null
+++ b/modules/ncspot/hm.nix
@@ -0,0 +1,36 @@
+{ config, lib, ... }:
+
+{
+ options.stylix.targets.ncspot.enable =
+ config.lib.stylix.mkEnableTarget "Ncspot" true;
+
+ config =
+ lib.mkIf (config.stylix.enable && config.stylix.targets.ncspot.enable)
+ {
+ programs.ncspot.settings =
+ let
+ colors = config.lib.stylix.colors.withHashtag;
+ in
+ {
+ theme = with colors; {
+ background = base00;
+ primary = base05;
+ secondary = base03;
+ title = base06;
+ playing = base05;
+ playing_selected = base06;
+ playing_bg = base02;
+ highlight = base05;
+ highlight_bg = base02;
+ error = base07;
+ error_bg = base0F;
+ statusbar = base00;
+ statusbar_progress = base04;
+ statusbar_bg = base04;
+ cmdline = base05;
+ cmdline_bg = base00;
+ search_match = base05;
+ };
+ };
+ };
+}
diff --git a/modules/neovim/hm.nix b/modules/neovim/hm.nix
new file mode 100644
index 0000000..024bed1
--- /dev/null
+++ b/modules/neovim/hm.nix
@@ -0,0 +1,73 @@
+{
+ pkgs,
+ config,
+ lib,
+ ...
+}:
+
+{
+ options.stylix.targets.neovim = {
+ enable = config.lib.stylix.mkEnableTarget "Neovim" true;
+ plugin = lib.mkOption {
+ type = lib.types.enum [
+ "base16-nvim"
+ "mini.base16"
+ ];
+ default = "mini.base16";
+ description = "Plugin used for the colorscheme";
+ };
+ transparentBackground = {
+ main = lib.mkEnableOption "background transparency for the main Neovim window";
+ signColumn = lib.mkEnableOption "background transparency for the Neovim sign column";
+ };
+ };
+
+ config =
+ lib.mkIf (config.stylix.enable && config.stylix.targets.neovim.enable)
+ {
+ programs.neovim =
+ let
+ cfg = config.stylix.targets.neovim;
+ in
+ {
+ plugins = [
+ (lib.mkIf (cfg.plugin == "base16-nvim") {
+ plugin = pkgs.vimPlugins.base16-nvim;
+ type = "lua";
+ config = with config.lib.stylix.colors.withHashtag; ''
+ require('base16-colorscheme').setup({
+ base00 = '${base00}', base01 = '${base01}', base02 = '${base02}', base03 = '${base03}',
+ base04 = '${base04}', base05 = '${base05}', base06 = '${base06}', base07 = '${base07}',
+ base08 = '${base08}', base09 = '${base09}', base0A = '${base0A}', base0B = '${base0B}',
+ base0C = '${base0C}', base0D = '${base0D}', base0E = '${base0E}', base0F = '${base0F}'
+ })
+ '';
+ })
+ (lib.mkIf (cfg.plugin == "mini.base16") {
+ plugin = pkgs.vimPlugins.mini-nvim;
+ type = "lua";
+ config = with config.lib.stylix.colors.withHashtag; ''
+ require('mini.base16').setup({
+ palette = {
+ base00 = '${base00}', base01 = '${base01}', base02 = '${base02}', base03 = '${base03}',
+ base04 = '${base04}', base05 = '${base05}', base06 = '${base06}', base07 = '${base07}',
+ base08 = '${base08}', base09 = '${base09}', base0A = '${base0A}', base0B = '${base0B}',
+ base0C = '${base0C}', base0D = '${base0D}', base0E = '${base0E}', base0F = '${base0F}'
+ }
+ })
+ '';
+ })
+ ];
+
+ extraLuaConfig = lib.mkMerge [
+ (lib.mkIf cfg.transparentBackground.main ''
+ vim.cmd.highlight({ "Normal", "guibg=NONE", "ctermbg=NONE" })
+ vim.cmd.highlight({ "NonText", "guibg=NONE", "ctermbg=NONE" })
+ '')
+ (lib.mkIf cfg.transparentBackground.signColumn ''
+ vim.cmd.highlight({ "SignColumn", "guibg=NONE", "ctermbg=NONE" })
+ '')
+ ];
+ };
+ };
+}
diff --git a/modules/nixos-icons/nixos.nix b/modules/nixos-icons/nixos.nix
new file mode 100644
index 0000000..e2fc721
--- /dev/null
+++ b/modules/nixos-icons/nixos.nix
@@ -0,0 +1,34 @@
+{
+ pkgs,
+ config,
+ lib,
+ ...
+}:
+
+with config.lib.stylix.colors;
+
+{
+ options.stylix.targets.nixos-icons.enable =
+ config.lib.stylix.mkEnableTarget "the NixOS logo" true;
+
+ config.nixpkgs.overlays =
+ lib.mkIf (config.stylix.enable && config.stylix.targets.nixos-icons.enable)
+ [
+ (_: super: {
+ nixos-icons = super.nixos-icons.overrideAttrs (oldAttrs: {
+ src = pkgs.applyPatches {
+ inherit (oldAttrs) src;
+ prePatch = ''
+ substituteInPlace logo/nix-snowflake-white.svg --replace-fail '#ffffff' '#${base05}'
+
+ # Insert attribution comment after the XML prolog
+ sed \
+ --in-place \
+ '2i' \
+ logo/nix-snowflake-white.svg
+ '';
+ };
+ });
+ })
+ ];
+}
diff --git a/modules/nixvim/darwin.nix b/modules/nixvim/darwin.nix
new file mode 100644
index 0000000..3bcbdf8
--- /dev/null
+++ b/modules/nixvim/darwin.nix
@@ -0,0 +1 @@
+import ./nixvim.nix
diff --git a/modules/nixvim/hm.nix b/modules/nixvim/hm.nix
new file mode 100644
index 0000000..3bcbdf8
--- /dev/null
+++ b/modules/nixvim/hm.nix
@@ -0,0 +1 @@
+import ./nixvim.nix
diff --git a/modules/nixvim/nixos.nix b/modules/nixvim/nixos.nix
new file mode 100644
index 0000000..3bcbdf8
--- /dev/null
+++ b/modules/nixvim/nixos.nix
@@ -0,0 +1 @@
+import ./nixvim.nix
diff --git a/modules/nixvim/nixvim.nix b/modules/nixvim/nixvim.nix
new file mode 100644
index 0000000..b87fb7c
--- /dev/null
+++ b/modules/nixvim/nixvim.nix
@@ -0,0 +1,142 @@
+{
+ config,
+ lib,
+ options,
+ ...
+}:
+let
+ cfg = config.stylix.targets.nixvim;
+in
+{
+ options.stylix.targets.nixvim = {
+ enable = config.lib.stylix.mkEnableTarget "nixvim" true;
+ plugin = lib.mkOption {
+ type = lib.types.enum [
+ "base16-nvim"
+ "mini.base16"
+ ];
+ default = "mini.base16";
+ description = "Plugin used for the colorscheme";
+ };
+ transparentBackground = {
+ main = lib.mkEnableOption "background transparency for the main NeoVim window";
+ signColumn = lib.mkEnableOption "background transparency for the NeoVim sign column";
+ };
+ };
+
+ imports = [
+ (lib.mkRenamedOptionModuleWith {
+ from = [
+ "stylix"
+ "targets"
+ "nixvim"
+ "transparent_bg"
+ "main"
+ ];
+ sinceRelease = 2411;
+ to = [
+ "stylix"
+ "targets"
+ "nixvim"
+ "transparentBackground"
+ "main"
+ ];
+ })
+
+ (lib.mkRenamedOptionModuleWith {
+ from = [
+ "stylix"
+ "targets"
+ "nixvim"
+ "transparent_bg"
+ "sign_column"
+ ];
+ sinceRelease = 2411;
+
+ to = [
+ "stylix"
+ "targets"
+ "nixvim"
+ "transparentBackground"
+ "signColumn"
+ ];
+ })
+ ];
+
+ config =
+ lib.mkIf (config.stylix.enable && cfg.enable && (config.programs ? nixvim))
+ (
+ lib.optionalAttrs (builtins.hasAttr "nixvim" options.programs) (
+ lib.mkMerge [
+ (lib.mkIf (cfg.plugin == "base16-nvim") {
+ programs.nixvim.colorschemes.base16 = {
+ enable = true;
+
+ colorscheme = {
+ inherit (config.lib.stylix.colors.withHashtag)
+ base00
+ base01
+ base02
+ base03
+ base04
+ base05
+ base06
+ base07
+ base08
+ base09
+ base0A
+ base0B
+ base0C
+ base0D
+ base0E
+ base0F
+ ;
+ };
+ };
+ })
+ (lib.mkIf (cfg.plugin == "mini.base16") {
+ programs.nixvim.plugins.mini = {
+ enable = true;
+
+ modules.base16.palette = {
+ inherit (config.lib.stylix.colors.withHashtag)
+ base00
+ base01
+ base02
+ base03
+ base04
+ base05
+ base06
+ base07
+ base08
+ base09
+ base0A
+ base0B
+ base0C
+ base0D
+ base0E
+ base0F
+ ;
+ };
+ };
+ })
+ {
+ programs.nixvim = {
+ highlight =
+ let
+ transparent = {
+ bg = "none";
+ ctermbg = "none";
+ };
+ in
+ {
+ Normal = lib.mkIf cfg.transparentBackground.main transparent;
+ NonText = lib.mkIf cfg.transparentBackground.main transparent;
+ SignColumn = lib.mkIf cfg.transparentBackground.signColumn transparent;
+ };
+ };
+ }
+ ]
+ )
+ );
+}
diff --git a/modules/nushell/hm.nix b/modules/nushell/hm.nix
new file mode 100644
index 0000000..a355b33
--- /dev/null
+++ b/modules/nushell/hm.nix
@@ -0,0 +1,50 @@
+{ config, lib, ... }:
+
+with config.lib.stylix.colors.withHashtag;
+
+{
+ options.stylix.targets.nushell.enable =
+ config.lib.stylix.mkEnableTarget "Nushell" true;
+
+ # Adapted from https://www.nushell.sh/book/coloring_and_theming.html#theming
+ config.programs.nushell.extraConfig =
+ lib.mkIf (config.stylix.enable && config.stylix.targets.nushell.enable)
+ ''
+ $env.config.color_config = {
+ separator: "${base03}"
+ leading_trailing_space_bg: "${base04}"
+ header: "${base0B}"
+ date: "${base0E}"
+ filesize: "${base0D}"
+ row_index: "${base0C}"
+ bool: "${base08}"
+ int: "${base0B}"
+ duration: "${base08}"
+ range: "${base08}"
+ float: "${base08}"
+ string: "${base04}"
+ nothing: "${base08}"
+ binary: "${base08}"
+ cellpath: "${base08}"
+ hints: dark_gray
+
+ shape_garbage: { fg: "${base07}" bg: "${base08}" }
+ shape_bool: "${base0D}"
+ shape_int: { fg: "${base0E}" attr: b }
+ shape_float: { fg: "${base0E}" attr: b }
+ shape_range: { fg: "${base0A}" attr: b }
+ shape_internalcall: { fg: "${base0C}" attr: b }
+ shape_external: "${base0C}"
+ shape_externalarg: { fg: "${base0B}" attr: b }
+ shape_literal: "${base0D}"
+ shape_operator: "${base0A}"
+ shape_signature: { fg: "${base0B}" attr: b }
+ shape_string: "${base0B}"
+ shape_filepath: "${base0D}"
+ shape_globpattern: { fg: "${base0D}" attr: b }
+ shape_variable: "${base0E}"
+ shape_flag: { fg: "${base0D}" attr: b }
+ shape_custom: { attr: b }
+ }
+ '';
+}
diff --git a/modules/plymouth/nixos.nix b/modules/plymouth/nixos.nix
new file mode 100644
index 0000000..05369f9
--- /dev/null
+++ b/modules/plymouth/nixos.nix
@@ -0,0 +1,84 @@
+{
+ config,
+ pkgs,
+ lib,
+ ...
+}:
+
+let
+ cfg = config.stylix.targets.plymouth;
+
+ theme = pkgs.runCommand "stylix-plymouth" { } ''
+ themeDir="$out/share/plymouth/themes/stylix"
+ mkdir -p $themeDir
+
+ ${pkgs.imagemagick}/bin/convert \
+ -background transparent \
+ -bordercolor transparent \
+ ${
+ # A transparent border ensures the image is not clipped when rotated
+ lib.optionalString cfg.logoAnimated "-border 42%"
+ } \
+ ${cfg.logo} \
+ $themeDir/logo.png
+
+ ${
+ if cfg.logoAnimated then
+ "cp ${./theme.script} $themeDir/stylix.script"
+ else
+ "cp ${./theme_still.script} $themeDir/stylix.script"
+ }
+
+ ${with config.lib.stylix.colors; ''
+ substituteInPlace $themeDir/stylix.script \
+ --replace-fail "%BASE00%" "${base00-dec-r}, ${base00-dec-g}, ${base00-dec-b}" \
+ --replace-fail "%BASE05%" "${base05-dec-r}, ${base05-dec-g}, ${base05-dec-b}"
+ ''}
+
+ echo "
+ [Plymouth Theme]
+ Name=Stylix
+ ModuleName=script
+
+ [script]
+ ImageDir=$themeDir
+ ScriptFile=$themeDir/stylix.script
+ " > $themeDir/stylix.plymouth
+ '';
+
+in
+{
+ options.stylix.targets.plymouth = {
+ enable = config.lib.stylix.mkEnableTarget "the Plymouth boot screen" true;
+
+ logo = lib.mkOption {
+ description = "Logo to be used on the boot screen.";
+ type = with lib.types; either path package;
+ defaultText = lib.literalMD "NixOS logo";
+
+ default = "${pkgs.nixos-icons}/share/icons/hicolor/256x256/apps/nix-snowflake.png";
+ };
+
+ logoAnimated = lib.mkOption {
+ description = ''
+ Whether to apply a spinning animation to the logo.
+
+ Disabling this allows the use of logos which don't have rotational
+ symmetry.
+ '';
+ type = lib.types.bool;
+ default = true;
+ };
+ };
+
+ imports = [
+ (lib.mkRemovedOptionModule [ "stylix" "targets" "plymouth" "blackBackground" ]
+ "This was removed since it goes against the chosen color scheme. If you want this, consider disabling the target and configuring Plymouth by hand."
+ )
+ ];
+
+ config.boot.plymouth = lib.mkIf cfg.enable {
+ theme = "stylix";
+ themePackages = [ theme ];
+ };
+}
diff --git a/modules/plymouth/theme.script b/modules/plymouth/theme.script
new file mode 100644
index 0000000..1faa412
--- /dev/null
+++ b/modules/plymouth/theme.script
@@ -0,0 +1,109 @@
+center_x = Window.GetWidth() / 2;
+center_y = Window.GetHeight() / 2;
+baseline_y = Window.GetHeight() * 0.9;
+
+
+### BACKGROUND ###
+
+Window.SetBackgroundTopColor(%BASE00%);
+Window.SetBackgroundBottomColor(%BASE00%);
+
+
+### LOGO ###
+
+logo.image = Image("logo.png");
+logo.sprite = Sprite(logo.image);
+logo.sprite.SetPosition(
+ center_x - (logo.image.GetWidth() / 2),
+ center_y - (logo.image.GetHeight() / 2),
+ 1
+);
+
+logo.spinner_active = 1;
+logo.spinner_third = 0;
+logo.spinner_index = 0;
+logo.spinner_max_third = 32;
+logo.spinner_max = logo.spinner_max_third * 3;
+
+real_index = 0;
+for (third = 0; third < 3; third++) {
+ for (index = 0; index < logo.spinner_max_third; index++) {
+ subthird = index / logo.spinner_max_third;
+ angle = (third + ((Math.Sin(Math.Pi * (subthird - 0.5)) / 2) + 0.5)) / 3;
+ logo.spinner_image[real_index] = logo.image.Rotate(2*Math.Pi * angle);
+ real_index++;
+ }
+}
+
+fun activate_spinner () {
+ logo.spinner_active = 1;
+}
+
+fun deactivate_spinner () {
+ logo.spinner_active = 0;
+ logo.sprite.SetImage(logo.image);
+}
+
+fun refresh_callback () {
+ if (logo.spinner_active) {
+ logo.spinner_index = (logo.spinner_index + 1) % (logo.spinner_max * 2);
+ logo.sprite.SetImage(logo.spinner_image[Math.Int(logo.spinner_index / 2)]);
+ }
+}
+
+Plymouth.SetRefreshFunction(refresh_callback);
+
+### PASSWORD ###
+
+prompt = null;
+bullets = null;
+bullet.image = Image.Text("•", %BASE05%);
+
+fun password_callback (prompt_text, bullet_count) {
+ deactivate_spinner();
+
+ prompt.image = Image.Text("Enter password", %BASE05%);
+ prompt.sprite = Sprite(prompt.image);
+ prompt.sprite.SetPosition(
+ center_x - (prompt.image.GetWidth() / 2),
+ baseline_y - prompt.image.GetHeight(),
+ 1
+ );
+
+ total_width = bullet_count * bullet.image.GetWidth();
+ start_x = center_x - (total_width / 2);
+
+ bullets = null;
+ for (i = 0; i < bullet_count; i++) {
+ bullets[i].sprite = Sprite(bullet.image);
+ bullets[i].sprite.SetPosition(
+ start_x + (i * bullet.image.GetWidth()),
+ baseline_y + bullet.image.GetHeight(),
+ 1
+ );
+ }
+}
+
+Plymouth.SetDisplayPasswordFunction(password_callback);
+
+
+### NORMAL ###
+
+fun normal_callback() {
+ prompt = null;
+ bullets = null;
+ activate_spinner();
+}
+
+Plymouth.SetDisplayNormalFunction(normal_callback);
+
+
+### QUIT ###
+
+fun quit_callback() {
+ prompt = null;
+ bullets = null;
+ deactivate_spinner();
+}
+
+Plymouth.SetQuitFunction(quit_callback);
diff --git a/modules/plymouth/theme_still.script b/modules/plymouth/theme_still.script
new file mode 100644
index 0000000..6608b03
--- /dev/null
+++ b/modules/plymouth/theme_still.script
@@ -0,0 +1,71 @@
+center_x = Window.GetWidth() / 2;
+center_y = Window.GetHeight() / 2;
+baseline_y = Window.GetHeight() * 0.9;
+
+
+### BACKGROUND ###
+
+Window.SetBackgroundTopColor(%BASE00%);
+Window.SetBackgroundBottomColor(%BASE00%);
+
+
+### LOGO ###
+
+logo.image = Image("logo.png");
+logo.sprite = Sprite(logo.image);
+logo.sprite.SetPosition(
+ center_x - (logo.image.GetWidth() / 2),
+ center_y - (logo.image.GetHeight() / 2),
+ 1
+);
+
+### PASSWORD ###
+
+prompt = null;
+bullets = null;
+bullet.image = Image.Text("•", %BASE05%);
+
+fun password_callback (prompt_text, bullet_count) {
+ prompt.image = Image.Text("Enter password", %BASE05%);
+ prompt.sprite = Sprite(prompt.image);
+ prompt.sprite.SetPosition(
+ center_x - (prompt.image.GetWidth() / 2),
+ baseline_y - prompt.image.GetHeight(),
+ 1
+ );
+
+ total_width = bullet_count * bullet.image.GetWidth();
+ start_x = center_x - (total_width / 2);
+
+ bullets = null;
+ for (i = 0; i < bullet_count; i++) {
+ bullets[i].sprite = Sprite(bullet.image);
+ bullets[i].sprite.SetPosition(
+ start_x + (i * bullet.image.GetWidth()),
+ baseline_y + bullet.image.GetHeight(),
+ 1
+ );
+ }
+}
+
+Plymouth.SetDisplayPasswordFunction(password_callback);
+
+
+### NORMAL ###
+
+fun normal_callback() {
+ prompt = null;
+ bullets = null;
+}
+
+Plymouth.SetDisplayNormalFunction(normal_callback);
+
+
+### QUIT ###
+
+fun quit_callback() {
+ prompt = null;
+ bullets = null;
+}
+
+Plymouth.SetQuitFunction(quit_callback);
diff --git a/modules/qutebrowser/hm.nix b/modules/qutebrowser/hm.nix
new file mode 100644
index 0000000..618342d
--- /dev/null
+++ b/modules/qutebrowser/hm.nix
@@ -0,0 +1,286 @@
+{ config, lib, ... }:
+
+with config.lib.stylix.colors.withHashtag;
+with config.stylix.fonts;
+
+let
+ background = base00;
+ secondary-background = base01;
+ selection-background = base03;
+
+ foreground = base05;
+ inverted-foreground = base00;
+
+ error = base08;
+
+ info = base0B;
+ secondary-info = base0C;
+
+ warning = base0E;
+in
+{
+ options.stylix.targets.qutebrowser.enable =
+ config.lib.stylix.mkEnableTarget "Qutebrowser" true;
+
+ config =
+ lib.mkIf (config.stylix.enable && config.stylix.targets.qutebrowser.enable)
+ {
+ programs.qutebrowser.settings = {
+ colors = {
+ completion = {
+ category = {
+ bg = background;
+ fg = info;
+
+ border = {
+ bottom = background;
+ top = background;
+ };
+ };
+
+ even.bg = background;
+ fg = foreground;
+
+ item.selected = {
+ bg = selection-background;
+
+ border = {
+ bottom = selection-background;
+ top = selection-background;
+ };
+
+ fg = foreground;
+ };
+
+ match.fg = info;
+ odd.bg = secondary-background;
+
+ scrollbar = {
+ bg = background;
+ fg = foreground;
+ };
+ };
+
+ contextmenu = {
+ disabled = {
+ bg = secondary-background;
+ fg = inverted-foreground;
+ };
+
+ menu = {
+ bg = background;
+ fg = foreground;
+ };
+
+ selected = {
+ bg = selection-background;
+ fg = foreground;
+ };
+ };
+
+ downloads = {
+ bar.bg = background;
+
+ error = {
+ bg = error;
+ fg = inverted-foreground;
+ };
+
+ start = {
+ bg = info;
+ fg = inverted-foreground;
+ };
+
+ stop = {
+ bg = secondary-info;
+ fg = inverted-foreground;
+ };
+ };
+
+ hints = {
+ bg = secondary-background;
+ fg = foreground;
+ match.fg = info;
+ };
+
+ keyhint = {
+ bg = background;
+ fg = foreground;
+ suffix.fg = foreground;
+ };
+
+ messages = {
+ error = {
+ bg = error;
+ fg = inverted-foreground;
+ border = error;
+ };
+
+ info = {
+ bg = info;
+ fg = inverted-foreground;
+ border = info;
+ };
+
+ warning = {
+ bg = warning;
+ fg = inverted-foreground;
+ border = warning;
+ };
+ };
+
+ prompts = {
+ bg = background;
+ border = background;
+ fg = foreground;
+ selected.bg = secondary-background;
+ };
+
+ statusbar = {
+ caret = {
+ bg = selection-background;
+ fg = foreground;
+
+ selection = {
+ bg = selection-background;
+ fg = foreground;
+ };
+ };
+
+ command = {
+ bg = background;
+ fg = foreground;
+
+ private = {
+ bg = secondary-background;
+ fg = foreground;
+ };
+ };
+
+ insert = {
+ bg = info;
+ fg = inverted-foreground;
+ };
+
+ normal = {
+ bg = background;
+ fg = foreground;
+ };
+
+ passthrough = {
+ bg = secondary-info;
+ fg = inverted-foreground;
+ };
+
+ private = {
+ bg = secondary-background;
+ fg = foreground;
+ };
+
+ progress.bg = info;
+
+ url = {
+ error.fg = error;
+ fg = foreground;
+ hover.fg = foreground;
+
+ success = {
+ http.fg = secondary-info;
+ https.fg = info;
+ };
+
+ warn.fg = warning;
+ };
+ };
+
+ tabs = {
+ bar.bg = background;
+
+ even = {
+ bg = secondary-background;
+ fg = foreground;
+ };
+
+ indicator = {
+ inherit error;
+ start = secondary-info;
+ stop = info;
+ };
+
+ odd = {
+ bg = background;
+ fg = foreground;
+ };
+
+ pinned = {
+ even = {
+ bg = info;
+ fg = inverted-foreground;
+ };
+
+ odd = {
+ bg = secondary-info;
+ fg = inverted-foreground;
+ };
+
+ selected = {
+ even = {
+ bg = selection-background;
+ fg = foreground;
+ };
+
+ odd = {
+ bg = selection-background;
+ fg = foreground;
+ };
+ };
+ };
+
+ selected = {
+ even = {
+ bg = selection-background;
+ fg = foreground;
+ };
+
+ odd = {
+ bg = selection-background;
+ fg = foreground;
+ };
+ };
+ };
+
+ webpage =
+ let
+ isDark = config.stylix.polarity == "dark";
+ in
+ {
+ darkmode.enabled = lib.mkIf isDark (lib.mkDefault true);
+
+ preferred_color_scheme = lib.mkIf isDark (lib.mkDefault config.stylix.polarity);
+ };
+ };
+
+ fonts = {
+ default_family = sansSerif.name;
+ default_size = "${toString sizes.applications}pt";
+
+ web = {
+ family = {
+ cursive = serif.name;
+ fantasy = serif.name;
+ fixed = monospace.name;
+ sans_serif = sansSerif.name;
+ serif = serif.name;
+ standard = sansSerif.name;
+ };
+
+ # TODO: Use the pixel unit:
+ # https://github.com/danth/stylix/issues/251.
+ size.default = builtins.floor (sizes.applications * 4 / 3 + 0.5);
+ };
+ };
+
+ hints.border = background;
+ };
+ };
+}
diff --git a/modules/qutebrowser/testbed.nix b/modules/qutebrowser/testbed.nix
new file mode 100644
index 0000000..1ef1c6c
--- /dev/null
+++ b/modules/qutebrowser/testbed.nix
@@ -0,0 +1,22 @@
+{ pkgs, ... }:
+
+let
+ package = pkgs.qutebrowser;
+
+in
+{
+ stylix.testbed.application = {
+ enable = true;
+ name = "org.qutebrowser.qutebrowser";
+ inherit package;
+ };
+
+ home-manager.sharedModules = [
+ {
+ programs.qutebrowser = {
+ enable = true;
+ inherit package;
+ };
+ }
+ ];
+}
diff --git a/modules/regreet/nixos.nix b/modules/regreet/nixos.nix
new file mode 100644
index 0000000..ac4b621
--- /dev/null
+++ b/modules/regreet/nixos.nix
@@ -0,0 +1,53 @@
+{
+ pkgs,
+ config,
+ lib,
+ ...
+}:
+
+{
+ options.stylix.targets.regreet.enable =
+ config.lib.stylix.mkEnableTarget "ReGreet" true;
+
+ config =
+ lib.mkIf
+ (
+ config.stylix.enable
+ && config.stylix.targets.regreet.enable
+ && pkgs.stdenv.hostPlatform.isLinux
+ )
+ {
+ programs.regreet = {
+ settings.background = {
+ path = config.stylix.image;
+ fit =
+ let
+ inherit (config.stylix) imageScalingMode;
+ in
+ if imageScalingMode == "fill" then
+ "Cover"
+ else if imageScalingMode == "fit" then
+ "Contain"
+ else if imageScalingMode == "stretch" then
+ "Fill"
+ # No other available options
+ else
+ null;
+ };
+ font = {
+ inherit (config.stylix.fonts.sansSerif) name package;
+ };
+ cursorTheme = {
+ inherit (config.stylix.cursor) name package;
+ };
+ theme = {
+ package = pkgs.adw-gtk3;
+ name = "adw-gtk3";
+ };
+ extraCss = config.lib.stylix.colors {
+ template = ./../gtk/gtk.mustache;
+ extension = "css";
+ };
+ };
+ };
+}
diff --git a/modules/river/hm.nix b/modules/river/hm.nix
new file mode 100644
index 0000000..6794480
--- /dev/null
+++ b/modules/river/hm.nix
@@ -0,0 +1,15 @@
+{ config, lib, ... }:
+
+{
+ options.stylix.targets.river.enable =
+ config.lib.stylix.mkEnableTarget "River" true;
+
+ config = lib.mkIf (config.stylix.enable && config.stylix.targets.river.enable) {
+ wayland.windowManager.river.settings = {
+ border-color-focused = "0x${config.lib.stylix.colors.base0D}";
+ border-color-unfocused = "0x${config.lib.stylix.colors.base03}";
+ border-color-urgent = "0x${config.lib.stylix.colors.base08}";
+ xcursor-theme = config.stylix.cursor.name;
+ };
+ };
+}
diff --git a/modules/rofi/hm.nix b/modules/rofi/hm.nix
new file mode 100644
index 0000000..c7a2fc2
--- /dev/null
+++ b/modules/rofi/hm.nix
@@ -0,0 +1,146 @@
+{ config, lib, ... }:
+
+with config.stylix.fonts;
+
+let
+ inherit (config.lib.formats.rasi) mkLiteral;
+ mkRgba =
+ opacity: color:
+ let
+ c = config.lib.stylix.colors;
+ r = c."${color}-rgb-r";
+ g = c."${color}-rgb-g";
+ b = c."${color}-rgb-b";
+ in
+ mkLiteral "rgba ( ${r}, ${g}, ${b}, ${opacity} % )";
+ mkRgb = mkRgba "100";
+ rofiOpacity = builtins.toString (
+ builtins.ceil (config.stylix.opacity.popups * 100)
+ );
+in
+{
+ options.stylix.targets.rofi.enable =
+ config.lib.stylix.mkEnableTarget "Rofi" true;
+
+ config = lib.mkIf (config.stylix.enable && config.stylix.targets.rofi.enable) {
+ programs.rofi = {
+ font = "${monospace.name} ${toString sizes.popups}";
+ theme = {
+ "*" = {
+ background = mkRgba rofiOpacity "base00";
+ lightbg = mkRgba rofiOpacity "base01";
+ red = mkRgba rofiOpacity "base08";
+ blue = mkRgba rofiOpacity "base0D";
+ lightfg = mkRgba rofiOpacity "base06";
+ foreground = mkRgba rofiOpacity "base05";
+
+ background-color = mkRgb "base00";
+ separatorcolor = mkLiteral "@foreground";
+ border-color = mkLiteral "@foreground";
+ selected-normal-foreground = mkLiteral "@lightbg";
+ selected-normal-background = mkLiteral "@lightfg";
+ selected-active-foreground = mkLiteral "@background";
+ selected-active-background = mkLiteral "@blue";
+ selected-urgent-foreground = mkLiteral "@background";
+ selected-urgent-background = mkLiteral "@red";
+ normal-foreground = mkLiteral "@foreground";
+ normal-background = mkLiteral "@background";
+ active-foreground = mkLiteral "@blue";
+ active-background = mkLiteral "@background";
+ urgent-foreground = mkLiteral "@red";
+ urgent-background = mkLiteral "@background";
+ alternate-normal-foreground = mkLiteral "@foreground";
+ alternate-normal-background = mkLiteral "@lightbg";
+ alternate-active-foreground = mkLiteral "@blue";
+ alternate-active-background = mkLiteral "@lightbg";
+ alternate-urgent-foreground = mkLiteral "@red";
+ alternate-urgent-background = mkLiteral "@lightbg";
+
+ # Text Colors
+ base-text = mkRgb "base05";
+ selected-normal-text = mkRgb "base01";
+ selected-active-text = mkRgb "base00";
+ selected-urgent-text = mkRgb "base00";
+ normal-text = mkRgb "base05";
+ active-text = mkRgb "base0D";
+ urgent-text = mkRgb "base08";
+ alternate-normal-text = mkRgb "base05";
+ alternate-active-text = mkRgb "base0D";
+ alternate-urgent-text = mkRgb "base08";
+ };
+
+ window.background-color = mkLiteral "@background";
+
+ message.border-color = mkLiteral "@separatorcolor";
+
+ textbox.text-color = mkLiteral "@base-text";
+
+ listview.border-color = mkLiteral "@separatorcolor";
+
+ element-text = {
+ background-color = mkLiteral "inherit";
+ text-color = mkLiteral "inherit";
+ };
+
+ element-icon = {
+ background-color = mkLiteral "inherit";
+ text-color = mkLiteral "inherit";
+ };
+
+ "element normal.normal" = {
+ background-color = mkLiteral "@normal-background";
+ text-color = mkLiteral "@normal-text";
+ };
+ "element normal.urgent" = {
+ background-color = mkLiteral "@urgent-background";
+ text-color = mkLiteral "@urgent-text";
+ };
+ "element normal.active" = {
+ background-color = mkLiteral "@active-background";
+ text-color = mkLiteral "@active-text";
+ };
+
+ "element selected.normal" = {
+ background-color = mkLiteral "@selected-normal-background";
+ text-color = mkLiteral "@selected-normal-text";
+ };
+ "element selected.urgent" = {
+ background-color = mkLiteral "@selected-urgent-background";
+ text-color = mkLiteral "@selected-urgent-text";
+ };
+ "element selected.active" = {
+ background-color = mkLiteral "@selected-active-background";
+ text-color = mkLiteral "@selected-active-text";
+ };
+
+ "element alternate.normal" = {
+ background-color = mkLiteral "@alternate-normal-background";
+ text-color = mkLiteral "@alternate-normal-text";
+ };
+ "element alternate.urgent" = {
+ background-color = mkLiteral "@alternate-urgent-background";
+ text-color = mkLiteral "@alternate-urgent-text";
+ };
+ "element alternate.active" = {
+ background-color = mkLiteral "@alternate-active-background";
+ text-color = mkLiteral "@alternate-active-text";
+ };
+
+ scrollbar.handle-color = mkLiteral "@normal-foreground";
+ sidebar.border-color = mkLiteral "@separatorcolor";
+ button.text-color = mkLiteral "@normal-text";
+ "button selected" = {
+ background-color = mkLiteral "@selected-normal-background";
+ text-color = mkLiteral "@selected-normal-text";
+ };
+
+ inputbar.text-color = mkLiteral "@normal-text";
+ case-indicator.text-color = mkLiteral "@normal-text";
+ entry.text-color = mkLiteral "@normal-text";
+ prompt.text-color = mkLiteral "@normal-text";
+
+ textbox-prompt-colon.text-color = mkLiteral "inherit";
+ };
+ };
+ };
+}
diff --git a/modules/spicetify/hm.nix b/modules/spicetify/hm.nix
new file mode 100644
index 0000000..0b3c9d4
--- /dev/null
+++ b/modules/spicetify/hm.nix
@@ -0,0 +1 @@
+import ./spicetify.nix
diff --git a/modules/spicetify/nixos.nix b/modules/spicetify/nixos.nix
new file mode 100644
index 0000000..0b3c9d4
--- /dev/null
+++ b/modules/spicetify/nixos.nix
@@ -0,0 +1 @@
+import ./spicetify.nix
diff --git a/modules/spicetify/spicetify.nix b/modules/spicetify/spicetify.nix
new file mode 100644
index 0000000..83aadf3
--- /dev/null
+++ b/modules/spicetify/spicetify.nix
@@ -0,0 +1,58 @@
+{
+ config,
+ options,
+ lib,
+ pkgs,
+ ...
+}:
+
+{
+ options.stylix.targets.spicetify.enable =
+ config.lib.stylix.mkEnableTarget "Spicetify" true;
+
+ config =
+ lib.mkIf
+ (
+ config.stylix.enable
+ && config.stylix.targets.spicetify.enable
+ && (config.programs ? spicetify)
+ )
+ (
+ lib.optionalAttrs (builtins.hasAttr "spicetify" options.programs) {
+ programs.spicetify = {
+ theme = {
+ name = "stylix";
+ src = pkgs.writeTextFile {
+ name = "color.ini";
+ destination = "/color.ini";
+ text = with config.lib.stylix.colors; ''
+ [base]
+ text = ${base05}
+ subtext = ${base05}
+ main = ${base00}
+ main-elevated = ${base02}
+ highlight = ${base02}
+ highlight-elevated = ${base03}
+ sidebar = ${base01}
+ player = ${base05}
+ card = ${base04}
+ shadow = ${base00}
+ selected-row = ${base05}
+ button = ${base05}
+ button-active = ${base05}
+ button-disabled = ${base04}
+ tab-active = ${base02}
+ notification = ${base02}
+ notification-error = ${base08}
+ equalizer = ${base0B}
+ misc = ${base02}
+ '';
+ };
+ # Sidebar configuration is incompatible with the default navigation bar
+ sidebarConfig = false;
+ };
+ colorScheme = "base";
+ };
+ }
+ );
+}
diff --git a/modules/sway/hm.nix b/modules/sway/hm.nix
new file mode 100644
index 0000000..8bbaba3
--- /dev/null
+++ b/modules/sway/hm.nix
@@ -0,0 +1,104 @@
+{ config, lib, ... }:
+
+with config.lib.stylix.colors.withHashtag;
+
+let
+ text = base05;
+ urgent = base08;
+ focused = base0D;
+ unfocused = base03;
+
+ fonts = {
+ names = [ config.stylix.fonts.sansSerif.name ];
+ size = config.stylix.fonts.sizes.desktop + 0.0;
+ };
+
+in
+{
+ options.stylix.targets.sway.enable =
+ config.lib.stylix.mkEnableTarget "Sway" true;
+
+ config = lib.mkMerge [
+ (lib.mkIf (config.stylix.enable && config.stylix.targets.sway.enable) {
+ wayland.windowManager.sway.config = {
+ inherit fonts;
+
+ colors =
+ let
+ background = base00;
+ indicator = base0B;
+ in
+ {
+ inherit background;
+ urgent = {
+ inherit background indicator text;
+ border = urgent;
+ childBorder = urgent;
+ };
+ focused = {
+ inherit background indicator text;
+ border = focused;
+ childBorder = focused;
+ };
+ focusedInactive = {
+ inherit background indicator text;
+ border = unfocused;
+ childBorder = unfocused;
+ };
+ unfocused = {
+ inherit background indicator text;
+ border = unfocused;
+ childBorder = unfocused;
+ };
+ placeholder = {
+ inherit background indicator text;
+ border = unfocused;
+ childBorder = unfocused;
+ };
+ };
+
+ output."*".bg = "${config.stylix.image} ${config.stylix.imageScalingMode}";
+ seat."*".xcursor_theme =
+ ''"${config.stylix.cursor.name}" ${toString config.stylix.cursor.size}'';
+ };
+ })
+
+ {
+ # Merge this with your bar configuration using //config.lib.stylix.sway.bar
+ lib.stylix.sway.bar = {
+ inherit fonts;
+
+ colors =
+ let
+ background = base01;
+ border = background;
+ in
+ {
+ inherit background;
+ statusline = text;
+ separator = base03;
+ focusedWorkspace = {
+ inherit text border;
+ background = focused;
+ };
+ activeWorkspace = {
+ inherit text border;
+ background = unfocused;
+ };
+ inactiveWorkspace = {
+ inherit text border;
+ background = unfocused;
+ };
+ urgentWorkspace = {
+ inherit text border;
+ background = urgent;
+ };
+ bindingMode = {
+ inherit text border;
+ background = urgent;
+ };
+ };
+ };
+ }
+ ];
+}
diff --git a/modules/swaylock/hm.nix b/modules/swaylock/hm.nix
new file mode 100644
index 0000000..1f0bdfb
--- /dev/null
+++ b/modules/swaylock/hm.nix
@@ -0,0 +1,71 @@
+{
+ pkgs,
+ options,
+ config,
+ lib,
+ ...
+}:
+
+with config.lib.stylix.colors;
+
+let
+ inside = base01-hex;
+ outside = base01-hex;
+ ring = base05-hex;
+ text = base05-hex;
+ positive = base0B-hex;
+ negative = base08-hex;
+
+in
+{
+ options.stylix.targets.swaylock = {
+ enable = config.lib.stylix.mkEnableTarget "Swaylock" true;
+ useImage = lib.mkOption {
+ description = ''
+ Whether to use your wallpaper image for the Swaylock background.
+ If this is disabled, a plain color will be used instead.
+ '';
+ type = lib.types.bool;
+ default = true;
+ };
+ };
+
+ config =
+ lib.mkIf
+ (
+ config.stylix.enable
+ && config.stylix.targets.swaylock.enable
+ && pkgs.stdenv.hostPlatform.isLinux
+ )
+ {
+ programs.swaylock.settings =
+ {
+ color = outside;
+ scaling = config.stylix.imageScalingMode;
+ inside-color = inside;
+ inside-clear-color = inside;
+ inside-caps-lock-color = inside;
+ inside-ver-color = inside;
+ inside-wrong-color = inside;
+ key-hl-color = positive;
+ layout-bg-color = inside;
+ layout-border-color = ring;
+ layout-text-color = text;
+ line-uses-inside = true;
+ ring-color = ring;
+ ring-clear-color = negative;
+ ring-caps-lock-color = ring;
+ ring-ver-color = positive;
+ ring-wrong-color = negative;
+ separator-color = "00000000";
+ text-color = text;
+ text-clear-color = text;
+ text-caps-lock-color = text;
+ text-ver-color = text;
+ text-wrong-color = text;
+ }
+ // lib.optionalAttrs config.stylix.targets.swaylock.useImage {
+ image = "${config.stylix.image}";
+ };
+ };
+}
diff --git a/modules/swaync/base.css b/modules/swaync/base.css
new file mode 100644
index 0000000..255a40a
--- /dev/null
+++ b/modules/swaync/base.css
@@ -0,0 +1,182 @@
+progress,
+progressbar,
+trough {
+ border: 1px solid @base0D;
+}
+
+trough {
+ background: @base01;
+}
+
+.notification.low,
+.notification.normal {
+ border: 1px solid @base0D;
+}
+
+.notification.low progress,
+.notification.normal progress {
+ background: @base0F;
+}
+
+.notification.critical {
+ border: 1px solid @base08;
+}
+
+.notification.critical progress {
+ background: @base08;
+}
+
+.summary {
+ color: @base05;
+}
+
+.body {
+ color: @base06;
+}
+
+.time {
+ color: @base06;
+}
+
+.notification-action {
+ color: @base05;
+ background: @base01;
+ border: 1px solid @base0D;
+}
+
+.notification-action:hover {
+ background: @base01;
+ color: @base05;
+}
+
+.notification-action:active {
+ background: @base0F;
+ color: @base05;
+}
+
+.close-button {
+ color: @base02;
+ background: @base08;
+}
+
+.close-button:hover {
+ background: lighter(@base08);
+ color: lighter(@base02);
+}
+
+.close-button:active {
+ background: @base08;
+ color: @base00;
+}
+
+.notification-content {
+ background: @base00;
+ border: 1px solid @base0D;
+}
+
+.floating-notifications.background .notification-row .notification-background {
+ background: transparent;
+ color: @base05;
+}
+
+.notification-group .notification-group-buttons,
+.notification-group .notification-group-headers {
+ color: @base05;
+}
+
+.notification-group .notification-group-headers .notification-group-icon {
+ color: @base05;
+}
+
+.notification-group .notification-group-headers .notification-group-header {
+ color: @base05;
+}
+
+.notification-group.collapsed .notification-row .notification {
+ background: @base01;
+}
+
+.notification-group.collapsed:hover
+ .notification-row:not(:only-child)
+ .notification {
+ background: @base01;
+}
+
+.control-center {
+ background: @base00;
+ border: 1px solid @base0D;
+ color: @base05;
+}
+
+.control-center .notification-row .notification-background {
+ background: @base00;
+ color: @base05;
+}
+
+.control-center .notification-row .notification-background:hover {
+ background: @base00;
+ color: @base05;
+}
+
+.control-center .notification-row .notification-background:active {
+ background: @base0F;
+ color: @base05;
+}
+
+.widget-title {
+ color: @base05;
+ margin: 0.5rem;
+}
+
+.widget-title > button {
+ background: @base01;
+ border: 1px solid @base0D;
+ color: @base05;
+}
+
+.widget-title > button:hover {
+ background: @base01;
+}
+
+.widget-dnd {
+ color: @base05;
+}
+
+.widget-dnd > switch {
+ background: @base01;
+ border: 1px solid @base0D;
+}
+
+.widget-dnd > switch:hover {
+ background: @base01;
+}
+
+.widget-dnd > switch:checked {
+ background: @base0F;
+}
+
+.widget-dnd > switch slider {
+ background: @base06;
+}
+
+.widget-mpris {
+ color: @base05;
+}
+
+.widget-mpris .widget-mpris-player {
+ background: @base01;
+ border: 1px solid @base0D;
+}
+
+.widget-mpris .widget-mpris-player button:hover {
+ background: @base01;
+}
+
+.widget-mpris .widget-mpris-player > box > button {
+ border: 1px solid @base0D;
+}
+
+.widget-mpris .widget-mpris-player > box > button:hover {
+ background: @base01;
+ border: 1px solid @base0D;
+}
diff --git a/modules/swaync/hm.nix b/modules/swaync/hm.nix
new file mode 100644
index 0000000..4433c92
--- /dev/null
+++ b/modules/swaync/hm.nix
@@ -0,0 +1,33 @@
+{
+ config,
+ lib,
+ ...
+}:
+
+with config.lib.stylix.colors.withHashtag;
+with config.stylix.fonts;
+
+{
+ options.stylix.targets.swaync = {
+ enable = config.lib.stylix.mkEnableTarget "SwayNC" true;
+ };
+
+ config =
+ lib.mkIf (config.stylix.enable && config.stylix.targets.swaync.enable)
+ {
+ services.swaync.style =
+ ''
+ @define-color base00 ${base00}; @define-color base01 ${base01}; @define-color base02 ${base02}; @define-color base03 ${base03};
+ @define-color base04 ${base04}; @define-color base05 ${base05}; @define-color base06 ${base06}; @define-color base07 ${base07};
+
+ @define-color base08 ${base08}; @define-color base09 ${base09}; @define-color base0A ${base0A}; @define-color base0B ${base0B};
+ @define-color base0C ${base0C}; @define-color base0D ${base0D}; @define-color base0E ${base0E}; @define-color base0F ${base0F};
+
+ * {
+ font-family: "${sansSerif.name}";
+ font-size: ${builtins.toString sizes.desktop}pt;
+ }
+ ''
+ + (builtins.readFile ./base.css);
+ };
+}
diff --git a/modules/sxiv/hm.nix b/modules/sxiv/hm.nix
new file mode 100644
index 0000000..827fc4f
--- /dev/null
+++ b/modules/sxiv/hm.nix
@@ -0,0 +1,20 @@
+{ config, lib, ... }:
+
+let
+ inherit (config.lib.stylix) colors;
+ inherit (config.stylix) fonts;
+in
+{
+ options.stylix.targets.sxiv.enable =
+ config.lib.stylix.mkEnableTarget "Sxiv" true;
+
+ config = lib.mkIf (config.stylix.enable && config.stylix.targets.sxiv.enable) {
+ xresources = {
+ properties = {
+ "Sxiv.foreground" = "#${colors.base01}";
+ "Sxiv.background" = "#${colors.base04}";
+ "Sxiv.font" = "${fonts.sansSerif.name}-${toString fonts.sizes.applications}";
+ };
+ };
+ };
+}
diff --git a/modules/tmux/hm.nix b/modules/tmux/hm.nix
new file mode 100644
index 0000000..ad3b869
--- /dev/null
+++ b/modules/tmux/hm.nix
@@ -0,0 +1,19 @@
+{ config, lib, ... }:
+
+let
+ theme = config.lib.stylix.colors {
+ templateRepo = config.lib.stylix.templates.tinted-tmux;
+ target = "base16";
+ };
+
+in
+{
+ options.stylix.targets.tmux.enable =
+ config.lib.stylix.mkEnableTarget "Tmux" true;
+
+ config = lib.mkIf (config.stylix.enable && config.stylix.targets.tmux.enable) {
+ programs.tmux.extraConfig = ''
+ source-file ${theme}
+ '';
+ };
+}
diff --git a/modules/tofi/hm.nix b/modules/tofi/hm.nix
new file mode 100644
index 0000000..fe05601
--- /dev/null
+++ b/modules/tofi/hm.nix
@@ -0,0 +1,41 @@
+{
+ config,
+ lib,
+ ...
+}:
+with config.stylix.fonts;
+with config.lib.stylix.colors.withHashtag;
+{
+ options.stylix.targets.tofi.enable =
+ config.lib.stylix.mkEnableTarget "Tofi" true;
+
+ config = lib.mkIf (config.stylix.enable && config.stylix.targets.tofi.enable) {
+ programs.tofi.settings =
+ let
+ opacity = lib.toHexString (
+ ((builtins.ceil (config.stylix.opacity.popups * 100)) * 255) / 100
+ );
+ background = base00 + opacity;
+ foreground = base05;
+ darkForeground = base04 + opacity;
+ selection = base03 + opacity;
+ in
+ {
+ font = monospace.name;
+ font-size = toString sizes.popups;
+ background-color = background;
+ outline-color = darkForeground;
+ border-color = foreground;
+ text-color = foreground;
+ prompt-color = base0A;
+ prompt-background = background;
+ placeholder-color = selection;
+ input-background = background;
+ default-result-background = background;
+ selection-color = selection;
+ selection-background = background;
+ border-width = lib.mkDefault 4;
+ outline-width = lib.mkDefault 2;
+ };
+ };
+}
diff --git a/modules/vesktop/hm.nix b/modules/vesktop/hm.nix
new file mode 100644
index 0000000..ded10d5
--- /dev/null
+++ b/modules/vesktop/hm.nix
@@ -0,0 +1,17 @@
+{ config, lib, ... }:
+let
+ themeFile = config.lib.stylix.colors {
+ template = ./template.mustache;
+ extension = ".css";
+ };
+in
+{
+ options.stylix.targets.vesktop.enable =
+ config.lib.stylix.mkEnableTarget "Vesktop" true;
+
+ config =
+ lib.mkIf (config.stylix.enable && config.stylix.targets.vesktop.enable)
+ {
+ xdg.configFile."vesktop/themes/stylix.theme.css".source = themeFile;
+ };
+}
diff --git a/modules/vesktop/template.mustache b/modules/vesktop/template.mustache
new file mode 100644
index 0000000..2a068cf
--- /dev/null
+++ b/modules/vesktop/template.mustache
@@ -0,0 +1,58 @@
+/**
+* @name Stylix
+* @author Stylix
+* @version 0.0.0
+* @description Theme configured via NixOS or Home Manager.
+**/
+
+:root {
+ --base00: #{{base00-hex}}; /* Black */
+ --base01: #{{base01-hex}}; /* Bright Black */
+ --base02: #{{base02-hex}}; /* Grey */
+ --base03: #{{base03-hex}}; /* Brighter Grey */
+ --base04: #{{base04-hex}}; /* Bright Grey */
+ --base05: #{{base05-hex}}; /* White */
+ --base06: #{{base06-hex}}; /* Brighter White */
+ --base07: #{{base07-hex}}; /* Bright White */
+ --base08: #{{base08-hex}}; /* Red */
+ --base09: #{{base09-hex}}; /* Orange */
+ --base0A: #{{base0A-hex}}; /* Yellow */
+ --base0B: #{{base0B-hex}}; /* Green */
+ --base0C: #{{base0C-hex}}; /* Cyan */
+ --base0D: #{{base0D-hex}}; /* Blue */
+ --base0E: #{{base0E-hex}}; /* Purple */
+ --base0F: #{{base0F-hex}}; /* Magenta */
+
+ --primary-630: var(--base00); /* Autocomplete background */
+ --primary-660: var(--base00); /* Search input background */
+}
+
+.theme-light, .theme-dark {
+ --search-popout-option-fade: none; /* Disable fade for search popout */
+ --bg-overlay-2: var(--base00); /* These 2 are needed for proper threads coloring */
+ --home-background: var(--base00);
+ --bg-overlay-chat : var(--base00); /* Recolor forum channels */
+ --background-primary: var(--base00);
+ --background-secondary: var(--base01);
+ --background-secondary-alt: var(--base01);
+ --channeltextarea-background: var(--base01);
+ --background-tertiary: var(--base00);
+ --background-accent: var(--base0E);
+ --background-floating: var(--base01);
+ --background-modifier-hover: #{{base00-hex}}4c; /* 30% of base00 */
+ --background-modifier-selected: var(--base00);
+ --text-normal: var(--base05);
+ --text-secondary: var(--base03);
+ --text-muted: var(--base04);
+ --text-link: var(--base0C);
+ --interactive-normal: var(--base05);
+ --interactive-hover: var(--base05);
+ --interactive-active: var(--base07);
+ --interactive-muted: var(--base03);
+ --channels-default: var(--base04);
+ --channel-icon: var(--base04);
+ --header-primary: var(--base06);
+ --header-secondary: var(--base04);
+ --scrollbar-thin-track: transparent;
+ --scrollbar-auto-track: transparent;
+}
diff --git a/modules/vesktop/testbed.nix b/modules/vesktop/testbed.nix
new file mode 100644
index 0000000..8035545
--- /dev/null
+++ b/modules/vesktop/testbed.nix
@@ -0,0 +1,15 @@
+{ pkgs, ... }:
+
+let
+ package = pkgs.vesktop;
+
+in
+{
+ stylix.testbed.application = {
+ enable = true;
+ name = "vesktop";
+ inherit package;
+ };
+
+ environment.systemPackages = [ package ];
+}
diff --git a/modules/vim/hm.nix b/modules/vim/hm.nix
new file mode 100644
index 0000000..ddf68d2
--- /dev/null
+++ b/modules/vim/hm.nix
@@ -0,0 +1,69 @@
+{
+ pkgs,
+ config,
+ lib,
+ ...
+}:
+
+let
+ themeFile = config.lib.stylix.colors {
+ templateRepo = config.lib.stylix.templates.base16-vim;
+ target = "base16";
+ };
+
+ themePlugin = pkgs.vimUtils.buildVimPlugin {
+ name = "stylix";
+ pname = "stylix";
+
+ src = themeFile;
+ dontUnpack = true;
+
+ buildPhase = ''
+ install -D $src $out/colors/base16-stylix.vim
+ '';
+ };
+
+ vimOptions =
+ let
+ inherit (config.stylix) fonts;
+ in
+ {
+ plugins = [ themePlugin ];
+ extraConfig = with config.lib.stylix.colors.withHashtag; ''
+ set termguicolors
+ colorscheme base16-stylix
+ unlet g:colors_name
+
+ let g:stylix_colors = {
+ \ 'base00': '${base00}',
+ \ 'base01': '${base01}',
+ \ 'base02': '${base02}',
+ \ 'base03': '${base03}',
+ \ 'base04': '${base04}',
+ \ 'base05': '${base05}',
+ \ 'base06': '${base06}',
+ \ 'base07': '${base07}',
+ \ 'base08': '${base08}',
+ \ 'base09': '${base09}',
+ \ 'base0A': '${base0A}',
+ \ 'base0B': '${base0B}',
+ \ 'base0C': '${base0C}',
+ \ 'base0D': '${base0D}',
+ \ 'base0E': '${base0E}',
+ \ 'base0F': '${base0F}',
+ \ }
+
+ set guifont=${
+ lib.escape [ " " ] fonts.monospace.name
+ }:h${toString fonts.sizes.terminal}
+ '';
+ };
+
+in
+{
+ options.stylix.targets.vim.enable = config.lib.stylix.mkEnableTarget "Vim" true;
+
+ config = lib.mkIf (config.stylix.enable && config.stylix.targets.vim.enable) {
+ programs.vim = vimOptions;
+ };
+}
diff --git a/modules/vscode/hm.nix b/modules/vscode/hm.nix
new file mode 100644
index 0000000..bbcffe4
--- /dev/null
+++ b/modules/vscode/hm.nix
@@ -0,0 +1,66 @@
+{
+ pkgs,
+ config,
+ lib,
+ ...
+}:
+
+with config.stylix.fonts;
+
+let
+ themeFile = config.lib.stylix.colors {
+ template = ./template.mustache;
+ extension = ".json";
+ };
+
+ themeExtension =
+ pkgs.runCommandLocal "stylix-vscode"
+ {
+ vscodeExtUniqueId = "stylix.stylix";
+ vscodeExtPublisher = "stylix";
+ version = "0.0.0";
+ }
+ ''
+ mkdir -p "$out/share/vscode/extensions/$vscodeExtUniqueId/themes"
+ ln -s ${./package.json} "$out/share/vscode/extensions/$vscodeExtUniqueId/package.json"
+ ln -s ${themeFile} "$out/share/vscode/extensions/$vscodeExtUniqueId/themes/stylix.json"
+ '';
+
+in
+{
+ options.stylix.targets.vscode.enable =
+ config.lib.stylix.mkEnableTarget "VSCode" true;
+
+ config =
+ lib.mkIf (config.stylix.enable && config.stylix.targets.vscode.enable)
+ {
+ programs.vscode = {
+ extensions = [ themeExtension ];
+ userSettings = {
+ "workbench.colorTheme" = "Stylix";
+ "editor.fontFamily" = monospace.name;
+ "editor.inlayHints.fontFamily" = monospace.name;
+ "editor.inlineSuggest.fontFamily" = monospace.name;
+ "scm.inputFontFamily" = monospace.name;
+ "debug.console.fontFamily" = monospace.name;
+ "markdown.preview.fontFamily" = sansSerif.name;
+ "chat.editor.fontFamily" = monospace.name;
+
+ # 4/3 factor used for pt to px;
+ "editor.fontSize" = sizes.terminal * 4.0 / 3.0;
+ "debug.console.fontSize" = sizes.terminal * 4.0 / 3.0;
+ "markdown.preview.fontSize" = sizes.terminal * 4.0 / 3.0;
+ "terminal.integrated.fontSize" = sizes.terminal * 4.0 / 3.0;
+ "chat.editor.fontSize" = sizes.terminal * 4.0 / 3.0;
+
+ # other factors (9/14, 13/14, 56/14) based on default for given value
+ # divided by default for `editor.fontSize` (14) from
+ # https://code.visualstudio.com/docs/getstarted/settings#_default-settings.
+ "editor.minimap.sectionHeaderFontSize" =
+ sizes.terminal * 4.0 / 3.0 * 9.0 / 14.0;
+ "scm.inputFontSize" = sizes.terminal * 4.0 / 3.0 * 13.0 / 14.0;
+ "screencastMode.fontSize" = sizes.terminal * 4.0 / 3.0 * 56.0 / 14.0;
+ };
+ };
+ };
+}
diff --git a/modules/vscode/package.json b/modules/vscode/package.json
new file mode 100644
index 0000000..7c6eee5
--- /dev/null
+++ b/modules/vscode/package.json
@@ -0,0 +1,18 @@
+{
+ "name": "stylix",
+ "displayName": "Stylix",
+ "version": "0.0.0",
+ "publisher": "stylix",
+ "description": "Theme configured via NixOS or Home Manager.",
+ "categories": [ "Themes" ],
+ "engines": {
+ "vscode": "^1.43.0"
+ },
+ "contributes": {
+ "themes": [{
+ "label": "Stylix",
+ "uiTheme": "vs",
+ "path": "./themes/stylix.json"
+ }]
+ }
+}
diff --git a/modules/vscode/template.mustache b/modules/vscode/template.mustache
new file mode 100644
index 0000000..8ccc195
--- /dev/null
+++ b/modules/vscode/template.mustache
@@ -0,0 +1,1508 @@
+{
+ "$schema": "vscode://schemas/color-theme",
+ "name": "{{scheme-name}}",
+ "type": "dark",
+ "colors": {
+ "contrastActiveBorder": null,
+ "contrastBorder": null,
+ "focusBorder": "#{{base0D-hex}}",
+ "foreground": "#{{base05-hex}}",
+ "disabledForeground": "#{{base04-hex}}",
+ "widget.border": "#{{base02-hex}}",
+ "widget.shadow": "#00000000",
+ "selection.background": "#{{base02-hex}}",
+ "descriptionForeground": "#{{base05-hex}}99",
+ "errorForeground": "#{{base08-hex}}",
+ "icon.foreground": "#{{base05-hex}}",
+ "sash.hoverBorder": null,
+ "window.activeBorder": null,
+ "window.inactiveBorder": null,
+ "textBlockQuote.background": "#{{base01-hex}}",
+ "textBlockQuote.border": "#{{base0D-hex}}",
+ "textCodeBlock.background": "#{{base00-hex}}",
+ "textLink.activeForeground": "#{{base0C-hex}}",
+ "textLink.foreground": "#{{base0D-hex}}",
+ "textPreformat.foreground": "#{{base0D-hex}}",
+ "textPreformat.background": null,
+ "textSeparator.foreground": "#{{base05-hex}}",
+ "toolbar.hoverBackground": "#{{base02-hex}}",
+ "toolbar.hoverOutline": null,
+ "toolbar.activeBackground": "#{{base02-hex}}",
+ "button.background": "#{{base0D-hex}}",
+ "button.foreground": "#{{base00-hex}}",
+ "button.border": null,
+ "button.separator": null,
+ "button.hoverBackground": "#{{base0D-hex}}C0",
+ "button.secondaryForeground": "#{{base00-hex}}",
+ "button.secondaryBackground": "#{{base0E-hex}}",
+ "button.secondaryHoverBackground": "#{{base0E-hex}}C0",
+ "checkbox.background": "#{{base00-hex}}",
+ "checkbox.foreground": "#{{base05-hex}}",
+ "checkbox.border": null,
+ "checkbox.selectBackground": null,
+ "checkbox.selectBorder": null,
+ "dropdown.background": "#{{base00-hex}}",
+ "dropdown.listBackground": "#{{base00-hex}}",
+ "dropdown.border": null,
+ "dropdown.foreground": "#{{base05-hex}}",
+ "input.background": "#{{base00-hex}}",
+ "input.border": null,
+ "input.foreground": "#{{base05-hex}}",
+ "input.placeholderForeground": "#{{base03-hex}}",
+ "inputOption.activeBackground": "#{{base0D-hex}}",
+ "inputOption.activeBorder": null,
+ "inputOption.activeForeground": "#{{base00-hex}}",
+ "inputOption.hoverBackground": null,
+ "inputValidation.errorBackground": "#{{base08-hex}}",
+ "inputValidation.errorForeground": "#{{base05-hex}}",
+ "inputValidation.errorBorder": "#{{base08-hex}}",
+ "inputValidation.infoBackground": "#{{base0D-hex}}",
+ "inputValidation.infoForeground": "#{{base05-hex}}",
+ "inputValidation.infoBorder": "#{{base0D-hex}}",
+ "inputValidation.warningBackground": "#{{base0A-hex}}",
+ "inputValidation.warningForeground": "#{{base05-hex}}",
+ "inputValidation.warningBorder": "#{{base0A-hex}}",
+ "scrollbar.shadow": "#00000000",
+ "scrollbarSlider.activeBackground": "#{{base04-hex}}77",
+ "scrollbarSlider.background": "#{{base03-hex}}33",
+ "scrollbarSlider.hoverBackground": "#{{base03-hex}}77",
+ "badge.foreground": "#{{base05-hex}}",
+ "badge.background": "#{{base00-hex}}",
+ "progressBar.background": "#{{base03-hex}}",
+ "list.activeSelectionBackground": "#{{base02-hex}}",
+ "list.activeSelectionForeground": "#{{base05-hex}}",
+ "list.activeSelectionIconForeground": null,
+ "list.dropBackground": "#{{base03-hex}}66",
+ "list.focusBackground": "#{{base02-hex}}",
+ "list.focusForeground": "#{{base05-hex}}",
+ "list.focusHighlightForeground": null,
+ "list.focusOutline": "#{{base0D-hex}}",
+ "list.focusAndSelectionOutline": "#{{base0D-hex}}",
+ "list.highlightForeground": "#{{base07-hex}}",
+ "list.hoverBackground": "#{{base02-hex}}",
+ "list.hoverForeground": "#{{base05-hex}}",
+ "list.inactiveSelectionBackground": "#{{base02-hex}}",
+ "list.inactiveSelectionForeground": "#{{base05-hex}}",
+ "list.inactiveSelectionIconForeground": null,
+ "list.inactiveFocusBackground": "#{{base02-hex}}",
+ "list.inactiveFocusOutline": "#{{base03-hex}}",
+ "list.invalidItemForeground": "#{{base08-hex}}",
+ "list.errorForeground": "#{{base08-hex}}",
+ "list.warningForeground": "#{{base0A-hex}}",
+ "listFilterWidget.background": "#{{base00-hex}}",
+ "listFilterWidget.outline": null,
+ "listFilterWidget.noMatchesOutline": "#{{base08-hex}}",
+ "listFilterWidget.shadow": "#00000000",
+ "list.filterMatchBackground": "#{{base02-hex}}",
+ "list.filterMatchBorder": null,
+ "list.deemphasizedForeground": null,
+ "list.dropBetweenBackground": null,
+ "tree.indentGuidesStroke": "#{{base05-hex}}",
+ "tree.inactiveIndentGuidesStroke": null,
+ "tree.tableColumnsBorder": null,
+ "tree.tableOddRowsBackground": null,
+ "activityBar.background": "#{{base01-hex}}",
+ "activityBar.dropBorder": "#{{base03-hex}}",
+ "activityBar.foreground": "#{{base05-hex}}",
+ "activityBar.inactiveForeground": "#{{base03-hex}}",
+ "activityBar.border": null,
+ "activityBarBadge.background": "#{{base0D-hex}}",
+ "activityBarBadge.foreground": "#{{base00-hex}}",
+ "activityBar.activeBorder": "#{{base05-hex}}",
+ "activityBar.activeBackground": "#{{base02-hex}}",
+ "activityBar.activeFocusBorder": "#{{base0D-hex}}",
+ "activityBarTop.foreground": "#{{base05-hex}}",
+ "activityBarTop.activeBorder": "#{{base0D-hex}}",
+ "activityBarTop.inactiveForeground": "#{{base03-hex}}",
+ "activityBarTop.dropBorder": "#{{base03-hex}}",
+ "profileBadge.background": "#{{base01-hex}}",
+ "profileBadge.foreground": "#{{base03-hex}}",
+ "sideBar.background": "#{{base01-hex}}",
+ "sideBar.foreground": "#{{base05-hex}}",
+ "sideBar.border": null,
+ "sideBar.dropBackground": "#{{base02-hex}}",
+ "sideBarTitle.foreground": "#{{base05-hex}}",
+ "sideBarSectionHeader.background": "#{{base01-hex}}",
+ "sideBarSectionHeader.foreground": "#{{base05-hex}}",
+ "sideBarSectionHeader.border": null,
+ "minimap.findMatchHighlight": "#{{base0A-hex}}",
+ "minimap.selectionHighlight": "#{{base02-hex}}",
+ "minimap.errorHighlight": "#{{base08-hex}}",
+ "minimap.warningHighlight": "#{{base0A-hex}}",
+ "minimap.background": "#{{base00-hex}}",
+ "minimap.selectionOccurrenceHighlight": "#{{base03-hex}}",
+ "minimap.foregroundOpacity": null,
+ "minimap.infoHighlight": null,
+ "minimapSlider.background": null,
+ "minimapSlider.hoverBackground": null,
+ "minimapSlider.activeBackground": null,
+ "minimapGutter.addedBackground": "#{{base0B-hex}}",
+ "minimapGutter.modifiedBackground": "#{{base0E-hex}}",
+ "minimapGutter.deletedBackground": "#{{base08-hex}}",
+ "editorGroup.border": null,
+ "editorGroup.dropBackground": "#{{base03-hex}}66",
+ "editorGroupHeader.noTabsBackground": "#{{base01-hex}}",
+ "editorGroupHeader.tabsBackground": "#{{base01-hex}}",
+ "editorGroupHeader.tabsBorder": null,
+ "editorGroupHeader.border": null,
+ "editorGroup.emptyBackground": "#{{base00-hex}}",
+ "editorGroup.focusedEmptyBorder": "#{{base0D-hex}}",
+ "editorGroup.dropIntoPromptForeground": "#{{base06-hex}}",
+ "editorGroup.dropIntoPromptBackground": "#{{base00-hex}}",
+ "editorGroup.dropIntoPromptBorder": null,
+ "tab.activeBackground": "#{{base02-hex}}",
+ "tab.unfocusedActiveBackground": "#{{base02-hex}}",
+ "tab.activeForeground": "#{{base05-hex}}",
+ "tab.border": "#00000000",
+ "tab.activeBorder": null,
+ "tab.dragAndDropBorder": "#{{base03-hex}}",
+ "tab.unfocusedActiveBorder": null,
+ "tab.activeBorderTop": null,
+ "tab.unfocusedActiveBorderTop": null,
+ "tab.lastPinnedBorder": null,
+ "tab.inactiveBackground": "#{{base01-hex}}",
+ "tab.unfocusedInactiveBackground": "#{{base01-hex}}",
+ "tab.inactiveForeground": "#{{base05-hex}}",
+ "tab.unfocusedActiveForeground": "#{{base04-hex}}",
+ "tab.unfocusedInactiveForeground": "#{{base04-hex}}",
+ "tab.hoverBackground": "#{{base02-hex}}",
+ "tab.unfocusedHoverBackground": "#{{base02-hex}}",
+ "tab.hoverForeground": "#{{base05-hex}}",
+ "tab.unfocusedHoverForeground": "#{{base05-hex}}",
+ "tab.hoverBorder": null,
+ "tab.unfocusedHoverBorder": null,
+ "tab.activeModifiedBorder": "#{{base0D-hex}}",
+ "tab.inactiveModifiedBorder": "#{{base0D-hex}}",
+ "tab.unfocusedActiveModifiedBorder": "#{{base0D-hex}}",
+ "tab.unfocusedInactiveModifiedBorder": "#{{base0D-hex}}",
+ "editorPane.background": "#{{base00-hex}}",
+ "sideBySideEditor.horizontalBorder": null,
+ "sideBySideEditor.verticalBorder": null,
+ "editor.background": "#{{base00-hex}}",
+ "editor.foreground": "#{{base05-hex}}",
+ "editorLineNumber.foreground": "#{{base03-hex}}",
+ "editorLineNumber.activeForeground": "#{{base04-hex}}",
+ "editorLineNumber.dimmedForeground": null,
+ "editorCursor.background": null,
+ "editorCursor.foreground": "#{{base05-hex}}",
+ "editor.selectionBackground": "#{{base02-hex}}",
+ "editor.selectionForeground": null,
+ "editor.inactiveSelectionBackground": "#{{base02-hex}}",
+ "editor.selectionHighlightBackground": "#{{base01-hex}}",
+ "editor.selectionHighlightBorder": null,
+ "editor.wordHighlightBackground": "#{{base02-hex}}",
+ "editor.wordHighlightBorder": null,
+ "editor.wordHighlightStrongBackground": "#{{base03-hex}}",
+ "editor.wordHighlightStrongBorder": null,
+ "editor.wordHighlightTextBackground": null,
+ "editor.wordHighlightTextBorder": null,
+ "editor.findMatchBackground": "#{{base0A-hex}}18",
+ "editor.findMatchHighlightBackground": "#{{base0A-hex}}66",
+ "editor.findRangeHighlightBackground": "#{{base01-hex}}",
+ "editor.findMatchBorder": "#{{base0A-hex}}",
+ "editor.findMatchHighlightBorder": null,
+ "editor.findRangeHighlightBorder": null,
+ "search.resultsInfoForeground": null,
+ "searchEditor.findMatchBackground": "#{{base0A-hex}}99",
+ "searchEditor.findMatchBorder": null,
+ "searchEditor.textInputBorder": null,
+ "editor.hoverHighlightBackground": "#{{base02-hex}}",
+ "editor.lineHighlightBackground": "#{{base01-hex}}",
+ "editor.lineHighlightBorder": null,
+ "editorWatermark.foreground": null,
+ "editorUnicodeHighlight.border": null,
+ "editorUnicodeHighlight.background": null,
+ "editorLink.activeForeground": "#{{base0D-hex}}",
+ "editor.rangeHighlightBackground": "#{{base01-hex}}",
+ "editor.rangeHighlightBorder": null,
+ "editor.symbolHighlightBackground": null,
+ "editor.symbolHighlightBorder": null,
+ "editorWhitespace.foreground": "#{{base03-hex}}",
+ "editorIndentGuide.background": "#{{base02-hex}}",
+ "editorIndentGuide.background1": null,
+ "editorIndentGuide.background2": null,
+ "editorIndentGuide.background3": null,
+ "editorIndentGuide.background4": null,
+ "editorIndentGuide.background5": null,
+ "editorIndentGuide.background6": null,
+ "editorIndentGuide.activeBackground": "#{{base02-hex}}",
+ "editorIndentGuide.activeBackground1": null,
+ "editorIndentGuide.activeBackground2": null,
+ "editorIndentGuide.activeBackground3": null,
+ "editorIndentGuide.activeBackground4": null,
+ "editorIndentGuide.activeBackground5": null,
+ "editorIndentGuide.activeBackground6": null,
+ "editorInlayHint.background": "#{{base01-hex}}",
+ "editorInlayHint.foreground": "#{{base03-hex}}",
+ "editorInlayHint.typeForeground": "#{{base03-hex}}",
+ "editorInlayHint.typeBackground": "#{{base01-hex}}",
+ "editorInlayHint.parameterForeground": "#{{base03-hex}}",
+ "editorInlayHint.parameterBackground": "#{{base01-hex}}",
+ "editorRuler.foreground": "#{{base02-hex}}",
+ "editor.linkedEditingBackground": null,
+ "editorCodeLens.foreground": "#{{base02-hex}}",
+ "editorLightBulb.foreground": "#{{base0A-hex}}",
+ "editorLightBulbAutoFix.foreground": "#{{base0D-hex}}",
+ "editorLightBulbAi.foreground": null,
+ "editorBracketMatch.background": "#{{base02-hex}}",
+ "editorBracketMatch.border": null,
+ "editorBracketHighlight.foreground1": "#{{base08-hex}}",
+ "editorBracketHighlight.foreground2": "#{{base09-hex}}",
+ "editorBracketHighlight.foreground3": "#{{base0A-hex}}",
+ "editorBracketHighlight.foreground4": "#{{base0B-hex}}",
+ "editorBracketHighlight.foreground5": "#{{base0D-hex}}",
+ "editorBracketHighlight.foreground6": "#{{base0E-hex}}",
+ "editorBracketHighlight.unexpectedBracket.foreground": "#{{base0F-hex}}",
+ "editorBracketPairGuide.activeBackground1": null,
+ "editorBracketPairGuide.activeBackground2": null,
+ "editorBracketPairGuide.activeBackground3": null,
+ "editorBracketPairGuide.activeBackground4": null,
+ "editorBracketPairGuide.activeBackground5": null,
+ "editorBracketPairGuide.activeBackground6": null,
+ "editorBracketPairGuide.background1": null,
+ "editorBracketPairGuide.background2": null,
+ "editorBracketPairGuide.background3": null,
+ "editorBracketPairGuide.background4": null,
+ "editorBracketPairGuide.background5": null,
+ "editorBracketPairGuide.background6": null,
+ "editor.foldBackground": null,
+ "editorOverviewRuler.background": null,
+ "editorOverviewRuler.border": "#00000000",
+ "editorOverviewRuler.findMatchForeground": "#{{base0A-hex}}",
+ "editorOverviewRuler.rangeHighlightForeground": "#{{base03-hex}}",
+ "editorOverviewRuler.selectionHighlightForeground": "#{{base02-hex}}",
+ "editorOverviewRuler.wordHighlightForeground": "#{{base07-hex}}",
+ "editorOverviewRuler.wordHighlightStrongForeground": "#{{base0D-hex}}",
+ "editorOverviewRuler.wordHighlightTextForeground": null,
+ "editorOverviewRuler.modifiedForeground": "#{{base0E-hex}}",
+ "editorOverviewRuler.addedForeground": "#{{base0B-hex}}",
+ "editorOverviewRuler.deletedForeground": "#{{base08-hex}}",
+ "editorOverviewRuler.errorForeground": "#{{base08-hex}}",
+ "editorOverviewRuler.warningForeground": "#{{base0A-hex}}",
+ "editorOverviewRuler.infoForeground": "#{{base0C-hex}}",
+ "editorOverviewRuler.bracketMatchForeground": "#{{base06-hex}}",
+ "editorOverviewRuler.inlineChatInserted": null,
+ "editorOverviewRuler.inlineChatRemoved": null,
+ "editorError.foreground": "#{{base08-hex}}",
+ "editorError.border": null,
+ "editorError.background": null,
+ "editorWarning.foreground": "#{{base0A-hex}}",
+ "editorWarning.border": null,
+ "editorWarning.background": null,
+ "editorInfo.foreground": "#{{base0C-hex}}",
+ "editorInfo.border": null,
+ "editorInfo.background": null,
+ "editorHint.foreground": "#{{base0D-hex}}",
+ "editorHint.border": null,
+ "problemsErrorIcon.foreground": "#{{base08-hex}}",
+ "problemsWarningIcon.foreground": "#{{base0A-hex}}",
+ "problemsInfoIcon.foreground": "#{{base0C-hex}}",
+ "editorUnnecessaryCode.border": null,
+ "editorUnnecessaryCode.opacity": null,
+ "editorGutter.background": "#{{base00-hex}}",
+ "editorGutter.modifiedBackground": "#{{base0E-hex}}",
+ "editorGutter.addedBackground": "#{{base0B-hex}}",
+ "editorGutter.deletedBackground": "#{{base08-hex}}",
+ "editorGutter.commentRangeForeground": "#{{base04-hex}}",
+ "editorGutter.commentGlyphForeground": null,
+ "editorGutter.commentUnresolvedGlyphForeground": null,
+ "editorGutter.foldingControlForeground": "#{{base05-hex}}",
+ "editorCommentsWidget.resolvedBorder": null,
+ "editorCommentsWidget.unresolvedBorder": null,
+ "editorCommentsWidget.rangeBackground": null,
+ "editorCommentsWidget.rangeActiveBackground": null,
+ "editorCommentsWidget.replyInputBackground": null,
+ "diffEditor.insertedTextBackground": "#{{base0B-hex}}4c",
+ "diffEditor.insertedTextBorder": null,
+ "diffEditor.removedTextBackground": "#{{base08-hex}}4c",
+ "diffEditor.removedTextBorder": null,
+ "diffEditor.border": "#{{base02-hex}}",
+ "diffEditor.diagonalFill": "#{{base02-hex}}",
+ "diffEditor.insertedLineBackground": "#{{base0B-hex}}18",
+ "diffEditor.removedLineBackground": "#{{base08-hex}}18",
+ "diffEditorGutter.insertedLineBackground": "#{{base0B-hex}}99",
+ "diffEditorGutter.removedLineBackground": "#{{base08-hex}}99",
+ "diffEditorOverview.insertedForeground": "#{{base0B-hex}}99",
+ "diffEditorOverview.removedForeground": "#{{base08-hex}}99",
+ "diffEditor.unchangedRegionBackground": null,
+ "diffEditor.unchangedRegionForeground": null,
+ "diffEditor.unchangedRegionShadow": "#00000000",
+ "diffEditor.unchangedCodeBackground": null,
+ "diffEditor.move.border": null,
+ "diffEditor.moveActive.border": null,
+ "multiDiffEditor.headerBackground": null,
+ "multiDiffEditor.background": null,
+ "multiDiffEditor.border": null,
+ "chat.requestBorder": "#{{base02-hex}}",
+ "chat.requestBackground": "#{{base01-hex}}",
+ "chat.slashCommandBackground": "#{{base0D-hex}}",
+ "chat.slashCommandForeground": "#{{base00-hex}}",
+ "chat.avatarBackground": "#{{base0D-hex}}",
+ "chat.avatarForeground": "#{{base00-hex}}",
+ "inlineChat.background": "#{{base01-hex}}",
+ "inlineChat.border": "#{{base02-hex}}",
+ "inlineChat.shadow": "#00000000",
+ "inlineChat.regionHighlight": "#{{base01-hex}}",
+ "inlineChatInput.border": "#{{base02-hex}}",
+ "inlineChatInput.focusBorder": "#{{base0D-hex}}",
+ "inlineChatInput.placeholderForeground": "#{{base03-hex}}",
+ "inlineChatInput.background": "#{{base00-hex}}",
+ "inlineChatDiff.inserted": "#{{base0B-hex}}60",
+ "inlineChatDiff.removed": "#{{base08-hex}}60",
+ "interactive.activeCodeBorder": null,
+ "interactive.inactiveCodeBorder": null,
+ "editorWidget.foreground": "#{{base05-hex}}",
+ "editorWidget.background": "#{{base00-hex}}",
+ "editorWidget.border": "#{{base02-hex}}",
+ "editorWidget.resizeBorder": "#{{base0D-hex}}",
+ "editorSuggestWidget.background": "#{{base01-hex}}",
+ "editorSuggestWidget.border": "#{{base02-hex}}",
+ "editorSuggestWidget.foreground": "#{{base05-hex}}",
+ "editorSuggestWidget.focusHighlightForeground": "#{{base0D-hex}}",
+ "editorSuggestWidget.highlightForeground": "#{{base0D-hex}}",
+ "editorSuggestWidget.selectedBackground": "#{{base02-hex}}",
+ "editorSuggestWidget.selectedForeground": "#{{base05-hex}}",
+ "editorSuggestWidget.selectedIconForeground": "#{{base05-hex}}",
+ "editorSuggestWidgetStatus.foreground": null,
+ "editorHoverWidget.foreground": "#{{base05-hex}}",
+ "editorHoverWidget.background": "#{{base01-hex}}",
+ "editorHoverWidget.border": "#{{base02-hex}}",
+ "editorHoverWidget.highlightForeground": "#{{base0D-hex}}",
+ "editorHoverWidget.statusBarBackground": "#{{base01-hex}}",
+ "editorGhostText.border": null,
+ "editorGhostText.background": "#00000000",
+ "editorGhostText.foreground": "#{{base03-hex}}",
+ "editorStickyScroll.background": "#{{base00-hex}}",
+ "editorStickyScroll.border": "#{{base02-hex}}",
+ "editorStickyScroll.shadow": "#00000000",
+ "editorStickyScrollHover.background": "#{{base01-hex}}",
+ "debugExceptionWidget.background": "#{{base01-hex}}",
+ "debugExceptionWidget.border": null,
+ "editorMarkerNavigation.background": "#{{base01-hex}}",
+ "editorMarkerNavigationError.background": "#{{base08-hex}}",
+ "editorMarkerNavigationWarning.background": "#{{base0A-hex}}",
+ "editorMarkerNavigationInfo.background": "#{{base0D-hex}}",
+ "editorMarkerNavigationError.headerBackground": "#{{base08-hex}}20",
+ "editorMarkerNavigationWarning.headerBackground": "#{{base0A-hex}}20",
+ "editorMarkerNavigationInfo.headerBackground": "#{{base0C-hex}}20",
+ "peekView.border": null,
+ "peekViewEditor.background": "#{{base01-hex}}",
+ "peekViewEditorGutter.background": "#{{base01-hex}}",
+ "peekViewEditor.matchHighlightBackground": "#{{base09-hex}}",
+ "peekViewEditor.matchHighlightBorder": null,
+ "peekViewResult.background": "#{{base00-hex}}",
+ "peekViewResult.fileForeground": "#{{base05-hex}}",
+ "peekViewResult.lineForeground": "#{{base03-hex}}",
+ "peekViewResult.matchHighlightBackground": "#{{base09-hex}}",
+ "peekViewResult.selectionBackground": "#{{base02-hex}}",
+ "peekViewResult.selectionForeground": "#{{base05-hex}}",
+ "peekViewTitle.background": "#{{base02-hex}}",
+ "peekViewTitleDescription.foreground": "#{{base03-hex}}",
+ "peekViewTitleLabel.foreground": "#{{base05-hex}}",
+ "peekViewEditorStickyScroll.background": null,
+ "merge.currentHeaderBackground": "#{{base0D-hex}}66",
+ "merge.currentContentBackground": "#{{base0D-hex}}18",
+ "merge.incomingHeaderBackground": "#{{base0B-hex}}66",
+ "merge.incomingContentBackground": "#{{base0B-hex}}18",
+ "merge.border": null,
+ "merge.commonContentBackground": null,
+ "merge.commonHeaderBackground": null,
+ "editorOverviewRuler.currentContentForeground": "#{{base0D-hex}}",
+ "editorOverviewRuler.incomingContentForeground": "#{{base0B-hex}}",
+ "editorOverviewRuler.commonContentForeground": "#{{base0F-hex}}",
+ "editorOverviewRuler.commentForeground": null,
+ "editorOverviewRuler.commentUnresolvedForeground": null,
+ "mergeEditor.change.background": null,
+ "mergeEditor.change.word.background": null,
+ "mergeEditor.conflict.unhandledUnfocused.border": null,
+ "mergeEditor.conflict.unhandledFocused.border": "#{{base0D-hex}}",
+ "mergeEditor.conflict.handledUnfocused.border": null,
+ "mergeEditor.conflict.handledFocused.border": "#{{base0D-hex}}",
+ "mergeEditor.conflict.handled.minimapOverViewRuler": null,
+ "mergeEditor.conflict.unhandled.minimapOverViewRuler": null,
+ "mergeEditor.conflictingLines.background": null,
+ "mergeEditor.changeBase.background": null,
+ "mergeEditor.changeBase.word.background": null,
+ "mergeEditor.conflict.input1.background": null,
+ "mergeEditor.conflict.input2.background": null,
+ "panel.background": "#{{base01-hex}}",
+ "panel.border": "#00000000",
+ "panel.dropBorder": "#{{base01-hex}}",
+ "panelTitle.activeBorder": null,
+ "panelTitle.activeForeground": "#{{base05-hex}}",
+ "panelTitle.inactiveForeground": "#{{base03-hex}}",
+ "panelInput.border": null,
+ "panelSection.border": null,
+ "panelSection.dropBackground": null,
+ "panelSectionHeader.background": null,
+ "panelSectionHeader.foreground": null,
+ "panelSectionHeader.border": null,
+ "outputView.background": null,
+ "outputViewStickyScroll.background": null,
+ "statusBar.background": "#{{base01-hex}}",
+ "statusBar.foreground": "#{{base05-hex}}",
+ "statusBar.border": null,
+ "statusBar.debuggingBackground": "#{{base09-hex}}",
+ "statusBar.debuggingForeground": "#{{base00-hex}}",
+ "statusBar.debuggingBorder": null,
+ "statusBar.noFolderForeground": "#{{base05-hex}}",
+ "statusBar.noFolderBackground": "#{{base01-hex}}",
+ "statusBar.noFolderBorder": null,
+ "statusBarItem.activeBackground": "#{{base02-hex}}",
+ "statusBarItem.hoverForeground": "#{{base05-hex}}",
+ "statusBarItem.hoverBackground": "#{{base02-hex}}",
+ "statusBarItem.prominentForeground": "#{{base00-hex}}",
+ "statusBarItem.prominentBackground": "#{{base0E-hex}}",
+ "statusBarItem.prominentHoverForeground": "#{{base00-hex}}",
+ "statusBarItem.prominentHoverBackground": "#{{base0E-hex}}C0",
+ "statusBarItem.remoteBackground": "#{{base01-hex}}",
+ "statusBarItem.remoteForeground": "#{{base05-hex}}",
+ "statusBarItem.remoteHoverBackground": "#{{base02-hex}}",
+ "statusBarItem.remoteHoverForeground": "#{{base05-hex}}",
+ "statusBarItem.errorBackground": "#{{base08-hex}}",
+ "statusBarItem.errorForeground": "#{{base00-hex}}",
+ "statusBarItem.errorHoverBackground": "#{{base08-hex}}C0",
+ "statusBarItem.errorHoverForeground": "#{{base00-hex}}",
+ "statusBarItem.warningBackground": "#{{base0A-hex}}",
+ "statusBarItem.warningForeground": "#{{base00-hex}}",
+ "statusBarItem.warningHoverBackground": "#{{base0A-hex}}C0",
+ "statusBarItem.warningHoverForeground": "#{{base00-hex}}",
+ "statusBarItem.compactHoverBackground": "#{{base02-hex}}",
+ "statusBarItem.focusBorder": "#{{base0D-hex}}",
+ "statusBar.focusBorder": "#{{base0D-hex}}",
+ "statusBarItem.offlineBackground": "#{{base09-hex}}",
+ "statusBarItem.offlineForeground": "#{{base00-hex}}",
+ "statusBarItem.offlineHoverForeground": "#{{base00-hex}}",
+ "statusBarItem.offlineHoverBackground": "#{{base09-hex}}C0",
+ "titleBar.activeBackground": "#{{base00-hex}}",
+ "titleBar.activeForeground": "#{{base05-hex}}",
+ "titleBar.inactiveBackground": "#{{base01-hex}}",
+ "titleBar.inactiveForeground": "#{{base03-hex}}",
+ "titleBar.border": null,
+ "menubar.selectionForeground": "#{{base05-hex}}",
+ "menubar.selectionBackground": "#{{base01-hex}}",
+ "menubar.selectionBorder": null,
+ "menu.foreground": "#{{base05-hex}}",
+ "menu.background": "#{{base01-hex}}",
+ "menu.selectionForeground": "#{{base05-hex}}",
+ "menu.selectionBackground": "#{{base02-hex}}",
+ "menu.selectionBorder": null,
+ "menu.separatorBackground": "#{{base02-hex}}",
+ "menu.border": "#{{base02-hex}}",
+ "commandCenter.foreground": "#{{base05-hex}}",
+ "commandCenter.activeForeground": "#{{base07-hex}}",
+ "commandCenter.background": "#{{base00-hex}}",
+ "commandCenter.activeBackground": "#{{base01-hex}}",
+ "commandCenter.border": null,
+ "commandCenter.inactiveForeground": null,
+ "commandCenter.inactiveBorder": null,
+ "commandCenter.activeBorder": null,
+ "commandCenter.debuggingBackground": null,
+ "notificationCenter.border": null,
+ "notificationCenterHeader.foreground": "#{{base05-hex}}",
+ "notificationCenterHeader.background": "#{{base01-hex}}",
+ "notificationToast.border": null,
+ "notifications.foreground": "#{{base05-hex}}",
+ "notifications.background": "#{{base02-hex}}",
+ "notifications.border": null,
+ "notificationLink.foreground": "#{{base0D-hex}}",
+ "notificationsErrorIcon.foreground": "#{{base08-hex}}",
+ "notificationsWarningIcon.foreground": "#{{base0A-hex}}",
+ "notificationsInfoIcon.foreground": "#{{base0D-hex}}",
+ "banner.background": "#{{base02-hex}}",
+ "banner.foreground": "#{{base05-hex}}",
+ "banner.iconForeground": "#{{base0D-hex}}",
+ "extensionButton.prominentForeground": "#{{base00-hex}}",
+ "extensionButton.prominentBackground": "#{{base0B-hex}}",
+ "extensionButton.prominentHoverBackground": "#{{base0B-hex}}C0",
+ "extensionButton.background": "#{{base0D-hex}}",
+ "extensionButton.foreground": "#{{base00-hex}}",
+ "extensionButton.hoverBackground": "#{{base0D-hex}}C0",
+ "extensionButton.separator": "#00000000",
+ "extensionBadge.remoteBackground": "#{{base09-hex}}",
+ "extensionBadge.remoteForeground": "#{{base07-hex}}",
+ "extensionIcon.starForeground": "#{{base0A-hex}}",
+ "extensionIcon.verifiedForeground": "#{{base0D-hex}}",
+ "extensionIcon.preReleaseForeground": "#{{base09-hex}}",
+ "extensionIcon.sponsorForeground": null,
+ "pickerGroup.border": "#{{base02-hex}}",
+ "pickerGroup.foreground": "#{{base03-hex}}",
+ "quickInput.background": "#{{base01-hex}}",
+ "quickInput.foreground": "#{{base05-hex}}",
+ "quickInputList.focusBackground": "#{{base02-hex}}",
+ "quickInputList.focusForeground": "#{{base05-hex}}",
+ "quickInputList.focusIconForeground": "#{{base05-hex}}",
+ "quickInputTitle.background": "#{{base01-hex}}",
+ "keybindingLabel.background": "#{{base02-hex}}",
+ "keybindingLabel.foreground": "#{{base05-hex}}",
+ "keybindingLabel.border": null,
+ "keybindingLabel.bottomBorder": "#{{base02-hex}}",
+ "keybindingTable.headerBackground": "#{{base02-hex}}",
+ "keybindingTable.rowsBackground": "#{{base01-hex}}",
+ "terminal.background": "#{{base00-hex}}",
+ "terminal.border": null,
+ "terminal.foreground": "#{{base05-hex}}",
+ "terminal.ansiBlack": "#{{base00-hex}}",
+ "terminal.ansiBlue": "#{{base0D-hex}}",
+ "terminal.ansiBrightBlack": "#{{base03-hex}}",
+ "terminal.ansiBrightBlue": "#{{base0D-hex}}",
+ "terminal.ansiBrightCyan": "#{{base0C-hex}}",
+ "terminal.ansiBrightGreen": "#{{base0B-hex}}",
+ "terminal.ansiBrightMagenta": "#{{base0E-hex}}",
+ "terminal.ansiBrightRed": "#{{base08-hex}}",
+ "terminal.ansiBrightWhite": "#{{base07-hex}}",
+ "terminal.ansiBrightYellow": "#{{base0A-hex}}",
+ "terminal.ansiCyan": "#{{base0C-hex}}",
+ "terminal.ansiGreen": "#{{base0B-hex}}",
+ "terminal.ansiMagenta": "#{{base0E-hex}}",
+ "terminal.ansiRed": "#{{base08-hex}}",
+ "terminal.ansiWhite": "#{{base05-hex}}",
+ "terminal.ansiYellow": "#{{base0A-hex}}",
+ "terminal.selectionBackground": null,
+ "terminal.selectionForeground": null,
+ "terminal.inactiveSelectionBackground": null,
+ "terminal.findMatchBackground": null,
+ "terminal.findMatchBorder": null,
+ "terminal.findMatchHighlightBackground": null,
+ "terminal.findMatchHighlightBorder": null,
+ "terminal.hoverHighlightBackground": null,
+ "terminalCursor.background": null,
+ "terminalCursor.foreground": "#{{base05-hex}}",
+ "terminal.dropBackground": null,
+ "terminal.tab.activeBorder": null,
+ "terminalCommandDecoration.defaultBackground": null,
+ "terminalCommandDecoration.successBackground": null,
+ "terminalCommandDecoration.errorBackground": null,
+ "terminalOverviewRuler.cursorForeground": "#ff0000",
+ "terminalOverviewRuler.findMatchForeground": "#ff0000",
+ "terminalStickyScroll.background": null,
+ "terminalStickyScrollHover.background": null,
+ "debugToolBar.background": "#{{base01-hex}}",
+ "debugToolBar.border": null,
+ "editor.stackFrameHighlightBackground": null,
+ "editor.focusedStackFrameHighlightBackground": null,
+ "editor.inlineValuesForeground": null,
+ "editor.inlineValuesBackground": null,
+ "debugView.exceptionLabelForeground": null,
+ "debugView.exceptionLabelBackground": null,
+ "debugView.stateLabelForeground": "#{{base07-hex}}",
+ "debugView.stateLabelBackground": "#{{base0D-hex}}",
+ "debugView.valueChangedHighlight": "#{{base0D-hex}}",
+ "debugTokenExpression.name": "#{{base0E-hex}}",
+ "debugTokenExpression.value": "#{{base05-hex}}",
+ "debugTokenExpression.string": "#{{base0B-hex}}",
+ "debugTokenExpression.boolean": "#{{base09-hex}}",
+ "debugTokenExpression.number": "#{{base09-hex}}",
+ "debugTokenExpression.error": "#{{base08-hex}}",
+ "testing.iconFailed": "#{{base08-hex}}",
+ "testing.iconErrored": "#{{base0F-hex}}",
+ "testing.iconPassed": "#{{base0B-hex}}",
+ "testing.runAction": "#{{base04-hex}}",
+ "testing.iconQueued": "#{{base0A-hex}}",
+ "testing.iconUnset": "#{{base04-hex}}",
+ "testing.iconSkipped": "#{{base0E-hex}}",
+ "testing.peekBorder": null,
+ "testing.peekHeaderBackground": "#{{base01-hex}}",
+ "testing.message.error.decorationForeground": "#{{base05-hex}}",
+ "testing.message.error.lineBackground": "#{{base08-hex}}20",
+ "testing.message.info.decorationForeground": "#{{base05-hex}}",
+ "testing.message.info.lineBackground": "#{{base0D-hex}}20",
+ "testing.messagePeekBorder": null,
+ "testing.messagePeekHeaderBackground": null,
+ "testing.coveredBackground": null,
+ "testing.coveredBorder": null,
+ "testing.coveredGutterBackground": null,
+ "testing.uncoveredBranchBackground": null,
+ "testing.uncoveredBackground": null,
+ "testing.uncoveredBorder": null,
+ "testing.uncoveredGutterBackground": null,
+ "testing.coverCountBadgeBackground": null,
+ "testing.coverCountBadgeForeground": null,
+ "welcomePage.background": "#{{base00-hex}}",
+ "welcomePage.progress.background": "#{{base03-hex}}",
+ "welcomePage.progress.foreground": "#{{base0D-hex}}",
+ "welcomePage.tileBackground": "#{{base01-hex}}",
+ "welcomePage.tileHoverBackground": "#{{base02-hex}}",
+ "welcomePage.tileBorder": null,
+ "walkThrough.embeddedEditorBackground": "#{{base00-hex}}",
+ "walkthrough.stepTitle.foreground": null,
+ "gitDecoration.addedResourceForeground": "#{{base0B-hex}}",
+ "gitDecoration.modifiedResourceForeground": "#{{base0E-hex}}",
+ "gitDecoration.deletedResourceForeground": "#{{base08-hex}}",
+ "gitDecoration.renamedResourceForeground": "#{{base0C-hex}}",
+ "gitDecoration.stageModifiedResourceForeground": "#{{base0E-hex}}",
+ "gitDecoration.stageDeletedResourceForeground": "#{{base08-hex}}",
+ "gitDecoration.untrackedResourceForeground": "#{{base09-hex}}",
+ "gitDecoration.ignoredResourceForeground": "#{{base03-hex}}",
+ "gitDecoration.conflictingResourceForeground": "#{{base0A-hex}}",
+ "gitDecoration.submoduleResourceForeground": "#{{base0F-hex}}",
+ "settings.headerForeground": "#{{base05-hex}}",
+ "settings.modifiedItemIndicator": "#{{base0D-hex}}",
+ "settings.dropdownBackground": "#{{base01-hex}}",
+ "settings.dropdownForeground": "#{{base05-hex}}",
+ "settings.dropdownBorder": null,
+ "settings.dropdownListBorder": null,
+ "settings.checkboxBackground": "#{{base01-hex}}",
+ "settings.checkboxForeground": "#{{base05-hex}}",
+ "settings.checkboxBorder": null,
+ "settings.rowHoverBackground": "#{{base02-hex}}",
+ "settings.textInputBackground": "#{{base01-hex}}",
+ "settings.textInputForeground": "#{{base05-hex}}",
+ "settings.textInputBorder": null,
+ "settings.numberInputBackground": "#{{base01-hex}}",
+ "settings.numberInputForeground": "#{{base05-hex}}",
+ "settings.numberInputBorder": null,
+ "settings.focusedRowBackground": "#{{base02-hex}}",
+ "settings.focusedRowBorder": "#{{base0D-hex}}",
+ "settings.headerBorder": "#{{base05-hex}}",
+ "settings.sashBorder": "#{{base05-hex}}",
+ "settings.settingsHeaderHoverForeground": null,
+ "breadcrumb.foreground": "#{{base05-hex}}",
+ "breadcrumb.background": "#{{base01-hex}}",
+ "breadcrumb.focusForeground": "#{{base06-hex}}",
+ "breadcrumb.activeSelectionForeground": "#{{base07-hex}}",
+ "breadcrumbPicker.background": "#{{base01-hex}}",
+ "editor.snippetTabstopHighlightBackground": "#{{base02-hex}}",
+ "editor.snippetTabstopHighlightBorder": null,
+ "editor.snippetFinalTabstopHighlightBackground": "#{{base03-hex}}",
+ "editor.snippetFinalTabstopHighlightBorder": null,
+ "symbolIcon.arrayForeground": "#{{base05-hex}}",
+ "symbolIcon.booleanForeground": "#{{base09-hex}}",
+ "symbolIcon.classForeground": "#{{base0A-hex}}",
+ "symbolIcon.colorForeground": "#{{base05-hex}}",
+ "symbolIcon.constantForeground": "#{{base09-hex}}",
+ "symbolIcon.constructorForeground": "#{{base0D-hex}}",
+ "symbolIcon.enumeratorForeground": "#{{base09-hex}}",
+ "symbolIcon.enumeratorMemberForeground": "#{{base0D-hex}}",
+ "symbolIcon.eventForeground": "#{{base0A-hex}}",
+ "symbolIcon.fieldForeground": "#{{base08-hex}}",
+ "symbolIcon.fileForeground": "#{{base05-hex}}",
+ "symbolIcon.folderForeground": "#{{base05-hex}}",
+ "symbolIcon.functionForeground": "#{{base0D-hex}}",
+ "symbolIcon.interfaceForeground": "#{{base0D-hex}}",
+ "symbolIcon.keyForeground": "#{{base05-hex}}",
+ "symbolIcon.keywordForeground": "#{{base0E-hex}}",
+ "symbolIcon.methodForeground": "#{{base0D-hex}}",
+ "symbolIcon.moduleForeground": "#{{base05-hex}}",
+ "symbolIcon.namespaceForeground": "#{{base05-hex}}",
+ "symbolIcon.nullForeground": "#{{base0F-hex}}",
+ "symbolIcon.numberForeground": "#{{base09-hex}}",
+ "symbolIcon.objectForeground": "#{{base05-hex}}",
+ "symbolIcon.operatorForeground": "#{{base05-hex}}",
+ "symbolIcon.packageForeground": "#{{base05-hex}}",
+ "symbolIcon.propertyForeground": "#{{base05-hex}}",
+ "symbolIcon.referenceForeground": "#{{base05-hex}}",
+ "symbolIcon.snippetForeground": "#{{base05-hex}}",
+ "symbolIcon.stringForeground": "#{{base0B-hex}}",
+ "symbolIcon.structForeground": "#{{base0A-hex}}",
+ "symbolIcon.textForeground": "#{{base05-hex}}",
+ "symbolIcon.typeParameterForeground": "#{{base05-hex}}",
+ "symbolIcon.unitForeground": "#{{base05-hex}}",
+ "symbolIcon.variableForeground": "#{{base08-hex}}",
+ "debugIcon.breakpointForeground": "#{{base08-hex}}",
+ "debugIcon.breakpointDisabledForeground": "#{{base04-hex}}",
+ "debugIcon.breakpointUnverifiedForeground": "#{{base02-hex}}",
+ "debugIcon.breakpointCurrentStackframeForeground": "#{{base0A-hex}}",
+ "debugIcon.breakpointStackframeForeground": "#{{base0F-hex}}",
+ "debugIcon.startForeground": "#{{base0B-hex}}",
+ "debugIcon.pauseForeground": "#{{base0D-hex}}",
+ "debugIcon.stopForeground": "#{{base08-hex}}",
+ "debugIcon.disconnectForeground": "#{{base08-hex}}",
+ "debugIcon.restartForeground": "#{{base0B-hex}}",
+ "debugIcon.stepOverForeground": "#{{base0D-hex}}",
+ "debugIcon.stepIntoForeground": "#{{base0C-hex}}",
+ "debugIcon.stepOutForeground": "#{{base0E-hex}}",
+ "debugIcon.continueForeground": "#{{base0B-hex}}",
+ "debugIcon.stepBackForeground": "#{{base0F-hex}}",
+ "debugConsole.infoForeground": "#{{base05-hex}}",
+ "debugConsole.warningForeground": "#{{base0A-hex}}",
+ "debugConsole.errorForeground": "#{{base08-hex}}",
+ "debugConsole.sourceForeground": "#{{base05-hex}}",
+ "debugConsoleInputIcon.foreground": "#{{base05-hex}}",
+ "notebook.editorBackground": "#{{base00-hex}}",
+ "notebook.cellBorderColor": "#{{base03-hex}}",
+ "notebook.cellHoverBackground": "#{{base01-hex}}",
+ "notebook.cellInsertionIndicator": null,
+ "notebook.cellStatusBarItemHoverBackground": null,
+ "notebook.cellToolbarSeparator": "#{{base02-hex}}",
+ "notebook.cellEditorBackground": "#{{base00-hex}}",
+ "notebook.focusedCellBackground": "#{{base02-hex}}",
+ "notebook.focusedCellBorder": "#{{base0D-hex}}",
+ "notebook.focusedEditorBorder": "#{{base0D-hex}}",
+ "notebook.inactiveFocusedCellBorder": "#{{base03-hex}}",
+ "notebook.inactiveSelectedCellBorder": null,
+ "notebook.outputContainerBackgroundColor": null,
+ "notebook.outputContainerBorderColor": null,
+ "notebook.selectedCellBackground": "#{{base02-hex}}",
+ "notebook.selectedCellBorder": null,
+ "notebook.symbolHighlightBackground": null,
+ "notebookScrollbarSlider.activeBackground": null,
+ "notebookScrollbarSlider.background": null,
+ "notebookScrollbarSlider.hoverBackground": null,
+ "notebookStatusErrorIcon.foreground": "#{{base08-hex}}",
+ "notebookStatusRunningIcon.foreground": "#{{base0C-hex}}",
+ "notebookStatusSuccessIcon.foreground": "#{{base0B-hex}}",
+ "notebookEditorOverviewRuler.runningCellForeground": null,
+ "charts.foreground": "#{{base05-hex}}",
+ "charts.lines": "#{{base05-hex}}",
+ "charts.red": "#{{base08-hex}}",
+ "charts.blue": "#{{base0D-hex}}",
+ "charts.yellow": "#{{base0A-hex}}",
+ "charts.orange": "#{{base09-hex}}",
+ "charts.green": "#{{base0B-hex}}",
+ "charts.purple": "#{{base0E-hex}}",
+ "ports.iconRunningProcessForeground": "#{{base09-hex}}",
+ "commentsView.resolvedIcon": null,
+ "commentsView.unresolvedIcon": null,
+ "actionBar.toggledBackground": null,
+ "simpleFindWidget.sashBorder": null,
+ "scm.historyItemAdditionsForeground": null,
+ "scm.historyItemDeletionsForeground": null,
+ "scm.historyItemStatisticsBorder": null,
+ "scm.historyItemSelectedStatisticsBorder": null
+ },
+ "tokenColors": [
+ {
+ "name": "Comment",
+ "scope": [
+ "comment",
+ "punctuation.definition.comment"
+ ],
+ "settings": {
+ "fontStyle": "italic",
+ "foreground": "#{{base03-hex}}"
+ }
+ },
+ {
+ "name": "Variables, Parameters",
+ "scope": [
+ "variable",
+ "string constant.other.placeholder",
+ "entity.name.variable.parameter",
+ "entity.name.variable.local",
+ "variable.parameter"
+ ],
+ "settings": {
+ "foreground": "#{{base08-hex}}"
+ }
+ },
+ {
+ "name": "Properties",
+ "scope": [
+ "variable.other.object.property"
+ ],
+ "settings": {
+ "foreground": "#{{base0D-hex}}"
+ }
+ },
+ {
+ "name": "Colors",
+ "scope": [
+ "constant.other.color"
+ ],
+ "settings": {
+ "foreground": "#{{base0B-hex}}"
+ }
+ },
+ {
+ "name": "Invalid",
+ "scope": [
+ "invalid",
+ "invalid.illegal"
+ ],
+ "settings": {
+ "foreground": "#{{base08-hex}}"
+ }
+ },
+ {
+ "name": "Invalid - Deprecated",
+ "scope": [
+ "invalid.deprecated"
+ ],
+ "settings": {
+ "foreground": "#{{base0F-hex}}"
+ }
+ },
+ {
+ "name": "Keyword, Storage",
+ "scope": [
+ "keyword",
+ "keyword.other",
+ "keyword.other.using",
+ "keyword.other.namespace",
+ "keyword.other.class",
+ "keyword.other.new",
+ "keyword.other.event",
+ "keyword.other.this",
+ "keyword.other.await",
+ "keyword.other.var",
+ "keyword.other.package",
+ "keyword.other.import",
+ "variable.language.this",
+ "storage.type.ts",
+ "storage.modifier"
+ ],
+ "settings": {
+ "foreground": "#{{base0E-hex}}"
+ }
+ },
+ {
+ "name": "Keyword Control",
+ "scope": [
+ "keyword.control",
+ "keyword.control.flow",
+ "keyword.control.from",
+ "keyword.control.import",
+ "keyword.control.as"
+ ],
+ "settings": {
+ "foreground": "#{{base0E-hex}}"
+ }
+ },
+ {
+ "name": "Types, Primitives",
+ "scope": [
+ "keyword.type",
+ "storage.type.primitive"
+ ],
+ "settings": {
+ "foreground": "#{{base0C-hex}}"
+ }
+ },
+ {
+ "name": "Function",
+ "scope": [
+ "storage.type.function"
+ ],
+ "settings": {
+ "foreground": "#{{base0D-hex}}"
+ }
+ },
+ {
+ "name": "Operator, Misc",
+ "scope": [
+ "constant.other.color",
+ "punctuation",
+ "punctuation.section.class.end",
+ "meta.tag",
+ "punctuation.definition.tag",
+ "punctuation.separator.inheritance.php",
+ "punctuation.definition.tag.html",
+ "punctuation.definition.tag.begin.html",
+ "punctuation.definition.tag.end.html",
+ "keyword.other.template",
+ "keyword.other.substitution"
+ ],
+ "settings": {
+ "foreground": "#{{base05-hex}}"
+ }
+ },
+ {
+ "name": "Embedded",
+ "scope": [
+ "punctuation.section.embedded",
+ "variable.interpolation"
+ ],
+ "settings": {
+ "foreground": "#{{base0F-hex}}"
+ }
+ },
+ {
+ "name": "Tag",
+ "scope": [
+ "entity.name.tag",
+ "meta.tag.sgml",
+ "markup.deleted.git_gutter"
+ ],
+ "settings": {
+ "foreground": "#{{base08-hex}}"
+ }
+ },
+ {
+ "name": "Function, Special Method",
+ "scope": [
+ "entity.name.function",
+ "meta.function-call",
+ "variable.function",
+ "support.function",
+ "keyword.other.special-method"
+ ],
+ "settings": {
+ "foreground": "#{{base0D-hex}}"
+ }
+ },
+ {
+ "name": "Block Level Variables",
+ "scope": [
+ "meta.block variable.other"
+ ],
+ "settings": {
+ "foreground": "#{{base08-hex}}"
+ }
+ },
+ {
+ "name": "Other Variable, String Link",
+ "scope": [
+ "support.other.variable",
+ "string.other.link"
+ ],
+ "settings": {
+ "foreground": "#{{base08-hex}}"
+ }
+ },
+ {
+ "name": "Number, Constant, Function Argument, Tag Attribute, Embedded",
+ "scope": [
+ "constant.numeric",
+ "constant.language",
+ "support.constant",
+ "constant.character",
+ "constant.escape",
+ "keyword.other.unit"
+ ],
+ "settings": {
+ "foreground": "#{{base09-hex}}"
+ }
+ },
+ {
+ "name": "String, Symbols, Inherited Class, Markup Heading",
+ "scope": [
+ "string",
+ "constant.other.symbol",
+ "constant.other.key",
+ "entity.other.inherited-class",
+ "markup.heading",
+ "markup.inserted.git_gutter",
+ "meta.group.braces.curly constant.other.object.key.js string.unquoted.label.js"
+ ],
+ "settings": {
+ "fontStyle": "",
+ "foreground": "#{{base0B-hex}}"
+ }
+ },
+ {
+ "name": "Class, Support",
+ "scope": [
+ "entity.name",
+ "support.type",
+ "support.class",
+ "support.other.namespace.use.php",
+ "meta.use.php",
+ "support.other.namespace.php",
+ "markup.changed.git_gutter",
+ "support.type.sys-types"
+ ],
+ "settings": {
+ "foreground": "#{{base0A-hex}}"
+ }
+ },
+ {
+ "name": "Storage Type, Import Class",
+ "scope": [
+ "storage.type",
+ "storage.modifier.package",
+ "storage.modifier.import"
+ ],
+ "settings": {
+ "foreground": "#{{base0A-hex}}"
+ }
+ },
+ {
+ "name": "Fields",
+ "scope": [
+ "entity.name.variable.field"
+ ],
+ "settings": {
+ "foreground": "#{{base0D-hex}}"
+ }
+ },
+ {
+ "name": "Entity Types",
+ "scope": [
+ "support.type"
+ ],
+ "settings": {
+ "foreground": "#{{base0C-hex}}"
+ }
+ },
+ {
+ "name": "CSS Class and Support",
+ "scope": [
+ "source.css support.type.property-name",
+ "source.sass support.type.property-name",
+ "source.scss support.type.property-name",
+ "source.less support.type.property-name",
+ "source.stylus support.type.property-name",
+ "source.postcss support.type.property-name"
+ ],
+ "settings": {
+ "foreground": "#{{base0C-hex}}"
+ }
+ },
+ {
+ "name": "Sub-methods",
+ "scope": [
+ "entity.name.module.js",
+ "variable.import.parameter.js",
+ "variable.other.class.js"
+ ],
+ "settings": {
+ "foreground": "#{{base08-hex}}"
+ }
+ },
+ {
+ "name": "Language methods",
+ "scope": [
+ "variable.language"
+ ],
+ "settings": {
+ "fontStyle": "italic",
+ "foreground": "#{{base08-hex}}"
+ }
+ },
+ {
+ "name": "entity.name.method.js",
+ "scope": [
+ "entity.name.method.js"
+ ],
+ "settings": {
+ "fontStyle": "italic",
+ "foreground": "#{{base0D-hex}}"
+ }
+ },
+ {
+ "name": "meta.method.js",
+ "scope": [
+ "meta.class-method.js entity.name.function.js",
+ "variable.function.constructor"
+ ],
+ "settings": {
+ "foreground": "#{{base0D-hex}}"
+ }
+ },
+ {
+ "name": "Attributes",
+ "scope": [
+ "entity.other.attribute-name"
+ ],
+ "settings": {
+ "foreground": "#{{base0D-hex}}"
+ }
+ },
+ {
+ "name": "HTML Attributes",
+ "scope": [
+ "text.html.basic entity.other.attribute-name.html",
+ "text.html.basic entity.other.attribute-name"
+ ],
+ "settings": {
+ "fontStyle": "italic",
+ "foreground": "#{{base0A-hex}}"
+ }
+ },
+ {
+ "name": "CSS Classes",
+ "scope": [
+ "entity.other.attribute-name.class"
+ ],
+ "settings": {
+ "foreground": "#{{base0A-hex}}"
+ }
+ },
+ {
+ "name": "CSS ID's",
+ "scope": [
+ "source.sass keyword.control"
+ ],
+ "settings": {
+ "foreground": "#{{base0D-hex}}"
+ }
+ },
+ {
+ "name": "Inserted",
+ "scope": [
+ "markup.inserted"
+ ],
+ "settings": {
+ "foreground": "#{{base0B-hex}}"
+ }
+ },
+ {
+ "name": "Deleted",
+ "scope": [
+ "markup.deleted"
+ ],
+ "settings": {
+ "foreground": "#{{base08-hex}}"
+ }
+ },
+ {
+ "name": "Changed",
+ "scope": [
+ "markup.changed"
+ ],
+ "settings": {
+ "foreground": "#{{base0E-hex}}"
+ }
+ },
+ {
+ "name": "Regular Expressions",
+ "scope": [
+ "string.regexp"
+ ],
+ "settings": {
+ "foreground": "#{{base0C-hex}}"
+ }
+ },
+ {
+ "name": "Escape Characters",
+ "scope": [
+ "constant.character.escape"
+ ],
+ "settings": {
+ "foreground": "#{{base0C-hex}}"
+ }
+ },
+ {
+ "name": "URL",
+ "scope": [
+ "*url*",
+ "*link*",
+ "*uri*"
+ ],
+ "settings": {
+ "fontStyle": "underline"
+ }
+ },
+ {
+ "name": "Decorators",
+ "scope": [
+ "tag.decorator.js entity.name.tag.js",
+ "tag.decorator.js punctuation.definition.tag.js"
+ ],
+ "settings": {
+ "fontStyle": "italic",
+ "foreground": "#{{base0D-hex}}"
+ }
+ },
+ {
+ "name": "ES7 Bind Operator",
+ "scope": [
+ "source.js constant.other.object.key.js string.unquoted.label.js"
+ ],
+ "settings": {
+ "fontStyle": "italic",
+ "foreground": "#{{base0E-hex}}"
+ }
+ },
+ {
+ "name": "JSON Key - Level 0",
+ "scope": [
+ "source.json meta.structure.dictionary.json support.type.property-name.json"
+ ],
+ "settings": {
+ "foreground": "#{{base0D-hex}}"
+ }
+ },
+ {
+ "name": "JSON Key - Level 1",
+ "scope": [
+ "source.json meta.structure.dictionary.json meta.structure.dictionary.value.json meta.structure.dictionary.json support.type.property-name.json"
+ ],
+ "settings": {
+ "foreground": "#{{base0D-hex}}"
+ }
+ },
+ {
+ "name": "JSON Key - Level 2",
+ "scope": [
+ "source.json meta.structure.dictionary.json meta.structure.dictionary.value.json meta.structure.dictionary.json meta.structure.dictionary.value.json meta.structure.dictionary.json support.type.property-name.json"
+ ],
+ "settings": {
+ "foreground": "#{{base0D-hex}}"
+ }
+ },
+ {
+ "name": "JSON Key - Level 3",
+ "scope": [
+ "source.json meta.structure.dictionary.json meta.structure.dictionary.value.json meta.structure.dictionary.json meta.structure.dictionary.value.json meta.structure.dictionary.json meta.structure.dictionary.value.json meta.structure.dictionary.json support.type.property-name.json"
+ ],
+ "settings": {
+ "foreground": "#{{base0D-hex}}"
+ }
+ },
+ {
+ "name": "JSON Key - Level 4",
+ "scope": [
+ "source.json meta.structure.dictionary.json meta.structure.dictionary.value.json meta.structure.dictionary.json meta.structure.dictionary.value.json meta.structure.dictionary.json meta.structure.dictionary.value.json meta.structure.dictionary.json meta.structure.dictionary.value.json meta.structure.dictionary.json support.type.property-name.json"
+ ],
+ "settings": {
+ "foreground": "#{{base0D-hex}}"
+ }
+ },
+ {
+ "name": "JSON Key - Level 5",
+ "scope": [
+ "source.json meta.structure.dictionary.json meta.structure.dictionary.value.json meta.structure.dictionary.json meta.structure.dictionary.value.json meta.structure.dictionary.json meta.structure.dictionary.value.json meta.structure.dictionary.json meta.structure.dictionary.value.json meta.structure.dictionary.json meta.structure.dictionary.value.json meta.structure.dictionary.json support.type.property-name.json"
+ ],
+ "settings": {
+ "foreground": "#{{base0D-hex}}"
+ }
+ },
+ {
+ "name": "JSON Key - Level 6",
+ "scope": [
+ "source.json meta.structure.dictionary.json meta.structure.dictionary.value.json meta.structure.dictionary.json meta.structure.dictionary.value.json meta.structure.dictionary.json meta.structure.dictionary.value.json meta.structure.dictionary.json meta.structure.dictionary.value.json meta.structure.dictionary.json meta.structure.dictionary.value.json meta.structure.dictionary.json meta.structure.dictionary.value.json meta.structure.dictionary.json support.type.property-name.json"
+ ],
+ "settings": {
+ "foreground": "#{{base0D-hex}}"
+ }
+ },
+ {
+ "name": "JSON Key - Level 7",
+ "scope": [
+ "source.json meta.structure.dictionary.json meta.structure.dictionary.value.json meta.structure.dictionary.json meta.structure.dictionary.value.json meta.structure.dictionary.json meta.structure.dictionary.value.json meta.structure.dictionary.json meta.structure.dictionary.value.json meta.structure.dictionary.json meta.structure.dictionary.value.json meta.structure.dictionary.json meta.structure.dictionary.value.json meta.structure.dictionary.json meta.structure.dictionary.value.json meta.structure.dictionary.json support.type.property-name.json"
+ ],
+ "settings": {
+ "foreground": "#{{base0D-hex}}"
+ }
+ },
+ {
+ "name": "JSON Key - Level 8",
+ "scope": [
+ "source.json meta.structure.dictionary.json meta.structure.dictionary.value.json meta.structure.dictionary.json meta.structure.dictionary.value.json meta.structure.dictionary.json meta.structure.dictionary.value.json meta.structure.dictionary.json meta.structure.dictionary.value.json meta.structure.dictionary.json meta.structure.dictionary.value.json meta.structure.dictionary.json meta.structure.dictionary.value.json meta.structure.dictionary.json meta.structure.dictionary.value.json meta.structure.dictionary.json meta.structure.dictionary.value.json meta.structure.dictionary.json support.type.property-name.json"
+ ],
+ "settings": {
+ "foreground": "#{{base0D-hex}}"
+ }
+ },
+ {
+ "name": "Markdown - Plain",
+ "scope": [
+ "text.html.markdown",
+ "punctuation.definition.list_item.markdown"
+ ],
+ "settings": {
+ "foreground": "#{{base05-hex}}"
+ }
+ },
+ {
+ "name": "Markdown - Markup Raw Inline",
+ "scope": [
+ "text.html.markdown markup.inline.raw.markdown"
+ ],
+ "settings": {
+ "foreground": "#{{base0E-hex}}"
+ }
+ },
+ {
+ "name": "Markdown - Markup Raw Inline Punctuation",
+ "scope": [
+ "text.html.markdown markup.inline.raw.markdown punctuation.definition.raw.markdown"
+ ],
+ "settings": {
+ "foreground": "#{{base0C-hex}}"
+ }
+ },
+ {
+ "name": "Markdown - Line Break",
+ "scope": [
+ "text.html.markdown meta.dummy.line-break"
+ ],
+ "settings": {
+ "foreground": "#{{base03-hex}}"
+ }
+ },
+ {
+ "name": "Markdown - Heading",
+ "scope": [
+ "markdown.heading",
+ "markup.heading | markup.heading entity.name",
+ "markup.heading.markdown punctuation.definition.heading.markdown"
+ ],
+ "settings": {
+ "foreground": "#{{base0D-hex}}"
+ }
+ },
+ {
+ "name": "Markup - Italic",
+ "scope": [
+ "markup.italic"
+ ],
+ "settings": {
+ "fontStyle": "italic",
+ "foreground": "#{{base08-hex}}"
+ }
+ },
+ {
+ "name": "Markup - Bold",
+ "scope": [
+ "markup.bold",
+ "markup.bold string"
+ ],
+ "settings": {
+ "fontStyle": "bold",
+ "foreground": "#{{base08-hex}}"
+ }
+ },
+ {
+ "name": "Markup - Bold-Italic",
+ "scope": [
+ "markup.bold markup.italic",
+ "markup.italic markup.bold",
+ "markup.quote markup.bold",
+ "markup.bold markup.italic string",
+ "markup.italic markup.bold string",
+ "markup.quote markup.bold string"
+ ],
+ "settings": {
+ "fontStyle": "bold",
+ "foreground": "#{{base08-hex}}"
+ }
+ },
+ {
+ "name": "Markup - Underline",
+ "scope": [
+ "markup.underline"
+ ],
+ "settings": {
+ "fontStyle": "underline",
+ "foreground": "#{{base09-hex}}"
+ }
+ },
+ {
+ "name": "Markdown - Blockquote",
+ "scope": [
+ "markup.quote punctuation.definition.blockquote.markdown"
+ ],
+ "settings": {
+ "foreground": "#{{base0C-hex}}"
+ }
+ },
+ {
+ "name": "Markup - Quote",
+ "scope": [
+ "markup.quote"
+ ],
+ "settings": {
+ "fontStyle": "italic"
+ }
+ },
+ {
+ "name": "Markdown - Link",
+ "scope": [
+ "string.other.link.title.markdown"
+ ],
+ "settings": {
+ "foreground": "#{{base0D-hex}}"
+ }
+ },
+ {
+ "name": "Markdown - Link Description",
+ "scope": [
+ "string.other.link.description.title.markdown"
+ ],
+ "settings": {
+ "foreground": "#{{base0E-hex}}"
+ }
+ },
+ {
+ "name": "Markdown - Link Anchor",
+ "scope": [
+ "constant.other.reference.link.markdown"
+ ],
+ "settings": {
+ "foreground": "#{{base0A-hex}}"
+ }
+ },
+ {
+ "name": "Markup - Raw Block",
+ "scope": [
+ "markup.raw.block"
+ ],
+ "settings": {
+ "foreground": "#{{base0E-hex}}"
+ }
+ },
+ {
+ "name": "Markdown - Raw Block Fenced",
+ "scope": [
+ "markup.raw.block.fenced.markdown"
+ ],
+ "settings": {
+ "foreground": "#00000050"
+ }
+ },
+ {
+ "name": "Markdown - Fenced Bode Block",
+ "scope": [
+ "punctuation.definition.fenced.markdown"
+ ],
+ "settings": {
+ "foreground": "#00000050"
+ }
+ },
+ {
+ "name": "Markdown - Fenced Code Block Variable",
+ "scope": [
+ "markup.raw.block.fenced.markdown",
+ "variable.language.fenced.markdown"
+ ],
+ "settings": {
+ "foreground": "#{{base0E-hex}}"
+ }
+ },
+ {
+ "name": "Markdown - Fenced Language",
+ "scope": [
+ "variable.language.fenced.markdown"
+ ],
+ "settings": {
+ "foreground": "#{{base08-hex}}"
+ }
+ },
+ {
+ "name": "Markdown - Separator",
+ "scope": [
+ "meta.separator"
+ ],
+ "settings": {
+ "fontStyle": "bold",
+ "foreground": "#{{base0C-hex}}"
+ }
+ },
+ {
+ "name": "Markup - Table",
+ "scope": [
+ "markup.table"
+ ],
+ "settings": {
+ "foreground": "#{{base0E-hex}}"
+ }
+ },
+ {
+ "scope": "token.info-token",
+ "settings": {
+ "foreground": "#{{base0D-hex}}"
+ }
+ },
+ {
+ "scope": "token.warn-token",
+ "settings": {
+ "foreground": "#{{base0A-hex}}"
+ }
+ },
+ {
+ "scope": "token.error-token",
+ "settings": {
+ "foreground": "#{{base08-hex}}"
+ }
+ },
+ {
+ "scope": "token.debug-token",
+ "settings": {
+ "foreground": "#{{base0E-hex}}"
+ }
+ }
+ ]
+}
diff --git a/modules/vscode/testbed.nix b/modules/vscode/testbed.nix
new file mode 100644
index 0000000..5408573
--- /dev/null
+++ b/modules/vscode/testbed.nix
@@ -0,0 +1,23 @@
+{ pkgs, ... }:
+
+# We are using VSCodium because VSCode is an unfree package
+let
+ package = pkgs.vscodium;
+
+in
+{
+ stylix.testbed.application = {
+ enable = true;
+ name = "codium";
+ inherit package;
+ };
+
+ home-manager.sharedModules = [
+ {
+ programs.vscode = {
+ enable = true;
+ inherit package;
+ };
+ }
+ ];
+}
diff --git a/modules/vscode/update.py b/modules/vscode/update.py
new file mode 100755
index 0000000..87328b2
--- /dev/null
+++ b/modules/vscode/update.py
@@ -0,0 +1,36 @@
+#! /usr/bin/env nix-shell
+#! nix-shell -i python3 -p python3Packages.markdown-it-py python3Packages.requests
+
+# This script parses the reference page and updates our template with any
+# added or removed settings.
+#
+# New settings are null by default. VSCode can handle this gracefully, but
+# normally a value should be chosen before committing the update.
+#
+# This only updates 'colors' and not 'tokenColors' for now.
+
+import json
+import os
+from markdown_it import MarkdownIt
+import requests
+
+documentation = requests.get('https://raw.githubusercontent.com/microsoft/vscode-docs/main/api/references/theme-color.md').text
+
+color_names = [
+ token.children[0].content
+ for token in MarkdownIt().parse(documentation)
+ if token.type == 'inline' and token.children[0].type == 'code_inline'
+]
+
+template_path = os.path.join(os.path.dirname(__file__), 'template.mustache')
+
+with open(template_path, 'r') as template_file:
+ template = json.load(template_file)
+
+template['colors'] = {
+ color_name: template['colors'].get(color_name)
+ for color_name in color_names
+}
+
+with open(template_path, 'w') as template_file:
+ json.dump(template, template_file, indent=4)
\ No newline at end of file
diff --git a/modules/waybar/base.css b/modules/waybar/base.css
new file mode 100644
index 0000000..ee5f723
--- /dev/null
+++ b/modules/waybar/base.css
@@ -0,0 +1,60 @@
+#wireplumber,
+#pulseaudio,
+#sndio {
+ padding: 0 5px;
+}
+#wireplumber.muted,
+#pulseaudio.muted,
+#sndio.muted {
+ padding: 0 5px;
+}
+#upower,
+#battery {
+ padding: 0 5px;
+}
+#upower.charging,
+#battery.Charging {
+ padding: 0 5px;
+}
+#network {
+ padding: 0 5px;
+}
+#network.disconnected {
+ padding: 0 5px;
+}
+#user {
+ padding: 0 5px;
+}
+#clock {
+ padding: 0 5px;
+}
+#backlight {
+ padding: 0 5px;
+}
+#cpu {
+ padding: 0 5px;
+}
+#disk {
+ padding: 0 5px;
+}
+#idle_inhibitor {
+ padding: 0 5px;
+}
+#temperature {
+ padding: 0 5px;
+}
+#mpd {
+ padding: 0 5px;
+}
+#language {
+ padding: 0 5px;
+}
+#keyboard-state {
+ padding: 0 5px;
+}
+#memory {
+ padding: 0 5px;
+}
+#window {
+ padding: 0 5px;
+}
diff --git a/modules/waybar/colors.nix b/modules/waybar/colors.nix
new file mode 100644
index 0000000..b5860f4
--- /dev/null
+++ b/modules/waybar/colors.nix
@@ -0,0 +1,88 @@
+place: ''
+ window .modules-${place} #workspaces button {
+ background-color: @base07;
+ color: @base00;
+ }
+ .modules-${place} #wireplumber,
+ .modules-${place} #pulseaudio,
+ .modules-${place} #sndio {
+ background-color: @base09;
+ color: @base00;
+ }
+ .modules-${place} #workspaces button.focused,
+ .modules-${place} #workspaces button.active {
+ background: @base03;
+ }
+ .modules-${place} #workspaces button.urgent {
+ background-color: @base08;
+ }
+ .modules-${place} #wireplumber.muted,
+ .modules-${place} #pulseaudio.muted,
+ .modules-${place} #sndio.muted {
+ background-color: @base0C;
+ }
+ .modules-${place} #upower,
+ .modules-${place} #battery {
+ background-color: @base0D;
+ color: @base00;
+ }
+ .modules-${place} #upower.charging,
+ .modules-${place} #battery.Charging {
+ background-color: @base0E;
+ }
+ .modules-${place} #network {
+ background-color: @base0B;
+ color: @base00;
+ }
+ .modules-${place} #network.disconnected {
+ background-color: @base0C;
+ }
+ .modules-${place} #user {
+ background-color: @base0F;
+ color: @base00;
+ }
+ .modules-${place} #clock {
+ background-color: @base03;
+ color: @base00;
+ }
+ .modules-${place} #backlight {
+ background-color: @base0E;
+ color: @base00;
+ }
+ .modules-${place} #cpu {
+ background-color: @base0B;
+ color: @base00;
+ }
+ .modules-${place} #disk {
+ background-color: @base02;
+ color: @base00;
+ }
+ .modules-${place} #idle_inhibitor {
+ background-color: @base06;
+ color: @base00;
+ }
+ .modules-${place} #temperature {
+ background-color: @base07;
+ color: @base00;
+ }
+ .modules-${place} #mpd {
+ background-color: @base02;
+ color: @base00;
+ }
+ .modules-${place} #language {
+ background-color: @base02;
+ color: @base00;
+ }
+ .modules-${place} #keyboard-state {
+ background-color: @base03;
+ color: @base00;
+ }
+ .modules-${place} #memory {
+ background-color: @base09;
+ color: @base00;
+ }
+ .modules-${place} #window {
+ background-color: @base0C;
+ color: @base00;
+ }
+''
diff --git a/modules/waybar/hm.nix b/modules/waybar/hm.nix
new file mode 100644
index 0000000..6bbf0b1
--- /dev/null
+++ b/modules/waybar/hm.nix
@@ -0,0 +1,82 @@
+{ config, lib, ... }:
+with config.lib.stylix.colors.withHashtag;
+with config.stylix.fonts;
+let
+ colorlessModules = place: ''
+ .modules-${place} #workspaces button {
+ border-bottom: 3px solid transparent;
+ }
+ .modules-${place} #workspaces button.focused,
+ .modules-${place} #workspaces button.active {
+ border-bottom: 3px solid @base05;
+ }
+ '';
+in
+{
+ options.stylix.targets.waybar = {
+ enable = config.lib.stylix.mkEnableTarget "Waybar" true;
+ enableLeftBackColors = lib.mkOption {
+ type = lib.types.bool;
+ default = false;
+ description = "enables background colors on the left side of the bar";
+ };
+ enableCenterBackColors = lib.mkOption {
+ type = lib.types.bool;
+ default = false;
+ description = "enables background colors on the center of the bar";
+ };
+ enableRightBackColors = lib.mkOption {
+ type = lib.types.bool;
+ default = false;
+ description = "enables background colors on the right side of the bar";
+ };
+ };
+
+ config =
+ lib.mkIf (config.stylix.enable && config.stylix.targets.waybar.enable)
+ {
+ programs.waybar.style =
+ ''
+ @define-color base00 ${base00}; @define-color base01 ${base01}; @define-color base02 ${base02}; @define-color base03 ${base03};
+ @define-color base04 ${base04}; @define-color base05 ${base05}; @define-color base06 ${base06}; @define-color base07 ${base07};
+
+ @define-color base08 ${base08}; @define-color base09 ${base09}; @define-color base0A ${base0A}; @define-color base0B ${base0B};
+ @define-color base0C ${base0C}; @define-color base0D ${base0D}; @define-color base0E ${base0E}; @define-color base0F ${base0F};
+
+ * {
+ font-family: "${sansSerif.name}";
+ font-size: ${builtins.toString sizes.desktop}pt;
+ }
+
+ window#waybar, tooltip {
+ background: alpha(@base00, ${
+ with config.stylix.opacity; builtins.toString desktop
+ });
+ color: @base05;
+ }
+
+ tooltip {
+ border-color: @base0D;
+ }
+ ''
+ + (builtins.readFile ./base.css)
+ + (
+ if config.stylix.targets.waybar.enableLeftBackColors then
+ (import ./colors.nix "left")
+ else
+ colorlessModules "left"
+ )
+ + (
+ if config.stylix.targets.waybar.enableCenterBackColors then
+ (import ./colors.nix "center")
+ else
+ colorlessModules "center"
+ )
+ + (
+ if config.stylix.targets.waybar.enableRightBackColors then
+ (import ./colors.nix "right")
+ else
+ colorlessModules "right"
+ );
+ };
+}
diff --git a/modules/wezterm/hm.nix b/modules/wezterm/hm.nix
new file mode 100644
index 0000000..c5a4502
--- /dev/null
+++ b/modules/wezterm/hm.nix
@@ -0,0 +1,148 @@
+{ config, lib, ... }:
+
+let
+ colors = config.lib.stylix.colors.withHashtag;
+in
+{
+ options.stylix.targets.wezterm.enable =
+ config.lib.stylix.mkEnableTarget "wezterm" true;
+
+ config =
+ lib.mkIf
+ (
+ config.stylix.enable
+ && config.stylix.targets.wezterm.enable
+ && config.programs.wezterm.enable
+ )
+ {
+
+ programs.wezterm.colorSchemes.stylix = with colors; {
+ ansi = [
+ base00
+ base08
+ base0B
+ base0A
+ base0D
+ base0E
+ base0C
+ base05
+ ];
+ brights = [
+ base03
+ base08
+ base0B
+ base0A
+ base0D
+ base0E
+ base0C
+ base07
+ ];
+ background = base00;
+ cursor_bg = base05;
+ cursor_fg = base00;
+ compose_cursor = base06;
+ foreground = base05;
+ scrollbar_thumb = base01;
+ selection_bg = base05;
+ selection_fg = base00;
+ split = base03;
+ visual_bell = base09;
+ tab_bar = {
+ background = base01;
+ inactive_tab_edge = base01;
+ active_tab = {
+ bg_color = base00;
+ fg_color = base05;
+ };
+ inactive_tab = {
+ bg_color = base03;
+ fg_color = base05;
+ };
+ inactive_tab_hover = {
+ bg_color = base05;
+ fg_color = base00;
+ };
+ new_tab = {
+ bg_color = base03;
+ fg_color = base05;
+ };
+ new_tab_hover = {
+ bg_color = base05;
+ fg_color = base00;
+ };
+ };
+ };
+
+ xdg.configFile."wezterm/wezterm.lua".text =
+ with colors;
+ with config.stylix.fonts;
+ lib.mkForce ''
+ -- Generated by Stylix
+ local wezterm = require("wezterm")
+ wezterm.add_to_config_reload_watch_list(wezterm.config_dir)
+ local function stylix_wrapped_config()
+ ${config.programs.wezterm.extraConfig}
+ end
+ local stylix_base_config = wezterm.config_builder()
+ local stylix_user_config = stylix_wrapped_config()
+ stylix_base_config = {
+ color_scheme = "stylix",
+ font = wezterm.font_with_fallback {
+ "${monospace.name}",
+ "${emoji.name}",
+ },
+ font_size = ${builtins.toString sizes.terminal},
+ window_background_opacity = ${builtins.toString config.stylix.opacity.terminal},
+ window_frame = {
+ active_titlebar_bg = "${base03}",
+ active_titlebar_fg = "${base05}",
+ active_titlebar_border_bottom = "${base03}",
+ border_left_color = "${base01}",
+ border_right_color = "${base01}",
+ border_bottom_color = "${base01}",
+ border_top_color = "${base01}",
+ button_bg = "${base01}",
+ button_fg = "${base05}",
+ button_hover_bg = "${base05}",
+ button_hover_fg = "${base03}",
+ inactive_titlebar_bg = "${base01}",
+ inactive_titlebar_fg = "${base05}",
+ inactive_titlebar_border_bottom = "${base03}",
+ },
+ colors = {
+ tab_bar = {
+ background = "${base01}",
+ inactive_tab_edge = "${base01}",
+ active_tab = {
+ bg_color = "${base00}",
+ fg_color = "${base05}",
+ },
+ inactive_tab = {
+ bg_color = "${base03}",
+ fg_color = "${base05}",
+ },
+ inactive_tab_hover = {
+ bg_color = "${base05}",
+ fg_color = "${base00}",
+ },
+ new_tab = {
+ bg_color = "${base03}",
+ fg_color = "${base05}",
+ },
+ new_tab_hover = {
+ bg_color = "${base05}",
+ fg_color = "${base00}",
+ },
+ },
+ },
+ command_palette_bg_color = "${base01}",
+ command_palette_fg_color = "${base05}",
+ command_palette_font_size = ${builtins.toString sizes.popups},
+ }
+ for key, value in pairs(stylix_user_config) do
+ stylix_base_config[key] = value
+ end
+ return stylix_base_config
+ '';
+ };
+}
diff --git a/modules/wezterm/testbed.nix b/modules/wezterm/testbed.nix
new file mode 100644
index 0000000..67a8863
--- /dev/null
+++ b/modules/wezterm/testbed.nix
@@ -0,0 +1,22 @@
+{ pkgs, ... }:
+
+let
+ package = pkgs.wezterm;
+
+in
+{
+ stylix.testbed.application = {
+ enable = true;
+ name = "org.wezfurlong.wezterm";
+ inherit package;
+ };
+
+ home-manager.sharedModules = [
+ {
+ programs.wezterm = {
+ enable = true;
+ inherit package;
+ };
+ }
+ ];
+}
diff --git a/modules/wob/hm.nix b/modules/wob/hm.nix
new file mode 100644
index 0000000..ad68738
--- /dev/null
+++ b/modules/wob/hm.nix
@@ -0,0 +1,18 @@
+{ config, lib, ... }:
+
+{
+ options.stylix.targets.wob.enable = config.lib.stylix.mkEnableTarget "wob" true;
+
+ config = lib.mkIf (config.stylix.enable && config.stylix.targets.wob.enable) {
+ services.wob.settings = {
+ "" = {
+ border_color = config.lib.stylix.colors.base05;
+ background_color = config.lib.stylix.colors.base00;
+ bar_color = config.lib.stylix.colors.base0A;
+ overflow_bar_color = config.lib.stylix.colors.base08;
+ overflow_background_color = config.lib.stylix.colors.base00;
+ overflow_border_color = config.lib.stylix.colors.base05;
+ };
+ };
+ };
+}
diff --git a/modules/wofi/hm.nix b/modules/wofi/hm.nix
new file mode 100644
index 0000000..1db9114
--- /dev/null
+++ b/modules/wofi/hm.nix
@@ -0,0 +1,47 @@
+{
+ config,
+ lib,
+ ...
+}:
+with config.stylix.fonts;
+let
+ colors = config.lib.stylix.colors.withHashtag;
+in
+{
+ options.stylix.targets.wofi.enable =
+ config.lib.stylix.mkEnableTarget "wofi" config.programs.wofi.enable;
+
+ config = lib.mkIf (config.stylix.enable && config.stylix.targets.wofi.enable) {
+ programs.wofi.style = with colors; ''
+ window {
+ font-family: "${monospace.name}";
+ font-size: ${toString sizes.popups}pt;
+
+ background-color: ${base00};
+ color: ${base05};
+ }
+
+ #entry:nth-child(odd) {
+ background-color: ${base00};
+ }
+
+ #entry:nth-child(even) {
+ background-color: ${base01};
+ }
+
+ #entry:selected {
+ background-color: ${base02};
+ }
+
+ #input {
+ background-color: ${base01};
+ color: ${base04};
+ border-color: ${base02};
+ }
+
+ #input:focus {
+ border-color: ${base0A};
+ }
+ '';
+ };
+}
diff --git a/modules/wpaperd/hm.nix b/modules/wpaperd/hm.nix
new file mode 100644
index 0000000..d8ff92b
--- /dev/null
+++ b/modules/wpaperd/hm.nix
@@ -0,0 +1,19 @@
+{ config, lib, ... }:
+
+{
+ options.stylix.targets.wpaperd.enable =
+ config.lib.stylix.mkEnableTarget "wpaperd" true;
+
+ config =
+ lib.mkIf (config.stylix.enable && config.stylix.targets.wpaperd.enable)
+ {
+ programs.wpaperd.settings.any = {
+ path = "${config.stylix.image}";
+ mode =
+ let
+ inherit (config.stylix) imageScalingMode;
+ in
+ if imageScalingMode == "fill" then "fit" else imageScalingMode;
+ };
+ };
+}
diff --git a/modules/xfce/hm.nix b/modules/xfce/hm.nix
new file mode 100644
index 0000000..4c8a438
--- /dev/null
+++ b/modules/xfce/hm.nix
@@ -0,0 +1,19 @@
+{ config, lib, ... }:
+
+{
+ # Disabled by default due to https://github.com/danth/stylix/issues/180
+ options.stylix.targets.xfce.enable =
+ config.lib.stylix.mkEnableTarget "Xfce" false;
+
+ config = lib.mkIf (config.stylix.enable && config.stylix.targets.xfce.enable) {
+ xfconf.settings = with config.stylix.fonts; {
+ xfwm4 = {
+ "general/title_font" = "${sansSerif.name} ${toString sizes.desktop}";
+ };
+ xsettings = {
+ "Gtk/FontName" = "${sansSerif.name} ${toString sizes.applications}";
+ "Gtk/MonospaceFontName" = "${monospace.name} ${toString sizes.applications}";
+ };
+ };
+ };
+}
diff --git a/modules/xresources/hm.nix b/modules/xresources/hm.nix
new file mode 100644
index 0000000..1bfc504
--- /dev/null
+++ b/modules/xresources/hm.nix
@@ -0,0 +1,38 @@
+{ config, lib, ... }:
+
+{
+ options.stylix.targets.xresources.enable =
+ config.lib.stylix.mkEnableTarget "Xresources" true;
+
+ config =
+ lib.mkIf (config.stylix.enable && config.stylix.targets.xresources.enable)
+ {
+ xresources.properties =
+ with config.lib.stylix.colors.withHashtag;
+ with config.stylix.fonts;
+ {
+ "*.faceName" = monospace.name;
+ "*.faceSize" = toString sizes.terminal;
+ "*.renderFont" = true;
+ "*foreground" = base05;
+ "*background" = base00;
+ "*cursorColor" = base05;
+ "*color0" = base00;
+ "*color1" = base08;
+ "*color2" = base0B;
+ "*color3" = base0A;
+ "*color4" = base0D;
+ "*color5" = base0E;
+ "*color6" = base0C;
+ "*color7" = base05;
+ "*color8" = base03;
+ "*color9" = base09;
+ "*color10" = base01;
+ "*color11" = base02;
+ "*color12" = base04;
+ "*color13" = base06;
+ "*color14" = base0F;
+ "*color15" = base07;
+ };
+ };
+}
diff --git a/modules/yazi/hm.nix b/modules/yazi/hm.nix
new file mode 100644
index 0000000..1db383b
--- /dev/null
+++ b/modules/yazi/hm.nix
@@ -0,0 +1,143 @@
+# Based on the official catppuccin themes https://github.com/yazi-rs/themes
+{
+ config,
+ lib,
+ ...
+}:
+{
+ options.stylix.targets.yazi = {
+ enable = config.lib.stylix.mkEnableTarget "Yazi" true;
+ };
+
+ config = lib.mkIf (config.stylix.enable && config.stylix.targets.yazi.enable) {
+ programs.yazi.theme =
+ with config.lib.stylix.colors.withHashtag;
+ let
+ mkFg = fg: { inherit fg; };
+ mkBg = bg: { inherit bg; };
+ mkBoth = fg: bg: { inherit fg bg; };
+ mkSame = c: (mkBoth c c);
+ in
+ {
+ manager = rec {
+ # Reusing bat themes, since it's suggested in the stying guide
+ # https://yazi-rs.github.io/docs/configuration/theme#manager
+ syntect_theme = config.lib.stylix.colors {
+ template = ../bat/base16-stylix.mustache;
+ extension = ".tmTheme";
+ };
+
+ cwd = mkFg cyan;
+ hovered = (mkBoth base05 base03) // {
+ bold = true;
+ };
+ preview_hovered = hovered;
+ find_keyword = (mkFg green) // {
+ bold = true;
+ };
+ find_position = mkFg base05;
+ marker_selected = mkSame yellow;
+ marker_copied = mkSame green;
+ marker_cut = mkSame red;
+ tab_active = mkBoth base00 blue;
+ tab_inactive = mkBoth base05 base01;
+ border_style = mkFg base04;
+ };
+
+ mode = {
+ normal_main = (mkBoth base00 blue) // {
+ bold = true;
+ };
+ normal_alt = mkBoth blue base00;
+ select_main = (mkBoth base00 green) // {
+ bold = true;
+ };
+ select_alt = mkBoth green base00;
+ unset_main = (mkBoth base00 brown) // {
+ bold = true;
+ };
+ unset_alt = mkBoth brown base00;
+ };
+
+ status = {
+ progress_label = mkBoth base05 base00;
+ progress_normal = mkBoth base05 base00;
+ progress_error = mkBoth red base00;
+ perm_type = mkFg blue;
+ perm_read = mkFg yellow;
+ perm_write = mkFg red;
+ perm_exec = mkFg green;
+ perm_sep = mkFg cyan;
+ };
+
+ pick = {
+ border = mkFg blue;
+ active = mkFg magenta;
+ inactive = mkFg base05;
+ };
+
+ input = {
+ border = mkFg blue;
+ title = mkFg base05;
+ value = mkFg base05;
+ selected = mkBg base03;
+ };
+
+ completion = {
+ border = mkFg blue;
+ active = mkBoth magenta base03;
+ inactive = mkFg base05;
+ };
+
+ tasks = {
+ border = mkFg blue;
+ title = mkFg base05;
+ hovered = mkBoth base05 base03;
+ };
+
+ which = {
+ mask = mkBg base02;
+ cand = mkFg cyan;
+ rest = mkFg brown;
+ desc = mkFg base05;
+ separator_style = mkFg base04;
+ };
+
+ help = {
+ on = mkFg magenta;
+ run = mkFg cyan;
+ desc = mkFg base05;
+ hovered = mkBoth base05 base03;
+ footer = mkFg base05;
+ };
+
+ # https://github.com/sxyazi/yazi/blob/main/yazi-config/preset/theme.toml
+ filetype.rules =
+ let
+ mkRule = mime: fg: { inherit mime fg; };
+ in
+ [
+ (mkRule "image/*" cyan)
+ (mkRule "video/*" yellow)
+ (mkRule "audio/*" yellow)
+
+ (mkRule "application/zip" magenta)
+ (mkRule "application/gzip" magenta)
+ (mkRule "application/tar" magenta)
+ (mkRule "application/bzip" magenta)
+ (mkRule "application/bzip2" magenta)
+ (mkRule "application/7z-compressed" magenta)
+ (mkRule "application/rar" magenta)
+ (mkRule "application/xz" magenta)
+
+ (mkRule "application/doc" green)
+ (mkRule "application/pdf" green)
+ (mkRule "application/rtf" green)
+ (mkRule "application/vnd.*" green)
+
+ ((mkRule "inode/directory" blue) // { bold = true; })
+ (mkRule "*" base05)
+ ];
+ };
+ };
+}
diff --git a/modules/yazi/testbed.nix b/modules/yazi/testbed.nix
new file mode 100644
index 0000000..e7f3326
--- /dev/null
+++ b/modules/yazi/testbed.nix
@@ -0,0 +1,26 @@
+{ pkgs, ... }:
+
+let
+ package = pkgs.yazi;
+in
+
+{
+ stylix.testbed.application = {
+ enable = true;
+ name = "yazi";
+ inherit package;
+ };
+
+ home-manager.sharedModules = [
+ {
+ programs.yazi = {
+ enable = true;
+ inherit package;
+ };
+
+ home.packages = [
+ pkgs.nerd-fonts.fira-mono
+ ];
+ }
+ ];
+}
diff --git a/modules/zathura/hm.nix b/modules/zathura/hm.nix
new file mode 100644
index 0000000..3c2f747
--- /dev/null
+++ b/modules/zathura/hm.nix
@@ -0,0 +1,47 @@
+{ config, lib, ... }:
+
+{
+ options.stylix.targets.zathura.enable =
+ config.lib.stylix.mkEnableTarget "Zathura" true;
+
+ config =
+ lib.mkIf (config.stylix.enable && config.stylix.targets.zathura.enable)
+ {
+ programs.zathura.options =
+ let
+ highlightTransparency = "0.5";
+ getColorCh =
+ colorName: channel: config.lib.stylix.colors."${colorName}-rgb-${channel}";
+ rgb =
+ color:
+ ''rgb(${getColorCh color "r"}, ${getColorCh color "g"}, ${getColorCh color "b"})'';
+ rgba =
+ color:
+ ''rgba(${getColorCh color "r"}, ${getColorCh color "g"}, ${getColorCh color "b"}, ${highlightTransparency})'';
+ in
+ {
+ # Taken from here:
+ # https://github.com/doenerkebap/base16-zathura
+ default-bg = rgb "base00";
+ default-fg = rgb "base01";
+ statusbar-fg = rgb "base04";
+ statusbar-bg = rgb "base02";
+ inputbar-bg = rgb "base00";
+ inputbar-fg = rgb "base07";
+ notification-bg = rgb "base00";
+ notification-fg = rgb "base07";
+ notification-error-bg = rgb "base00";
+ notification-error-fg = rgb "base08";
+ notification-warning-bg = rgb "base00";
+ notification-warning-fg = rgb "base08";
+ highlight-color = rgba "base0A";
+ highlight-active-color = rgba "base0D";
+ completion-bg = rgb "base01";
+ completion-fg = rgb "base0D";
+ completion-highlight-fg = rgb "base07";
+ completion-highlight-bg = rgb "base0D";
+ recolor-lightcolor = rgb "base00";
+ recolor-darkcolor = rgb "base06";
+ };
+ };
+}
diff --git a/modules/zathura/testbed.nix b/modules/zathura/testbed.nix
new file mode 100644
index 0000000..861bfa0
--- /dev/null
+++ b/modules/zathura/testbed.nix
@@ -0,0 +1,22 @@
+{ pkgs, ... }:
+
+let
+ package = pkgs.zathura;
+
+in
+{
+ stylix.testbed.application = {
+ enable = true;
+ name = "org.pwmt.zathura";
+ inherit package;
+ };
+
+ home-manager.sharedModules = [
+ {
+ programs.zathura = {
+ enable = true;
+ inherit package;
+ };
+ }
+ ];
+}
diff --git a/modules/zellij/hm.nix b/modules/zellij/hm.nix
new file mode 100644
index 0000000..9e461f7
--- /dev/null
+++ b/modules/zellij/hm.nix
@@ -0,0 +1,35 @@
+{ config, lib, ... }:
+
+{
+ options.stylix.targets.zellij.enable =
+ config.lib.stylix.mkEnableTarget "zellij" true;
+
+ config =
+ lib.mkIf
+ (
+ config.stylix.enable
+ && config.stylix.targets.zellij.enable
+ && config.programs.zellij.enable
+ )
+ {
+ xdg.configFile."zellij/themes/stylix.kdl".text =
+ with config.lib.stylix.colors.withHashtag; ''
+ themes {
+ default {
+ bg "${base03}";
+ fg "${base05}";
+ red "${base01}";
+ green "${base0B}";
+ blue "${base0D}";
+ yellow "${base0A}";
+ magenta "${base0E}";
+ orange "${base09}";
+ cyan "${base0C}";
+ black "${base00}";
+ white "${base07}";
+ }
+ }
+ '';
+ };
+
+}
diff --git a/palette-generator/Ai/Evolutionary.hs b/palette-generator/Ai/Evolutionary.hs
new file mode 100644
index 0000000..c6a0c8b
--- /dev/null
+++ b/palette-generator/Ai/Evolutionary.hs
@@ -0,0 +1,127 @@
+{-# LANGUAGE MultiParamTypeClasses #-}
+
+module Ai.Evolutionary ( Species(..), evolve ) where
+
+import Data.Ord (Down (Down), comparing)
+import Data.Vector ((!))
+import qualified Data.Vector as V
+import Data.Vector.Algorithms.Intro (selectBy)
+import System.Random (randomRIO)
+import Text.Printf (printf)
+
+numSurvivors :: Int
+numSurvivors = 500
+
+numNewborns :: Int
+numNewborns = 50000 - numSurvivors
+
+mutationProbability :: Double
+mutationProbability = 0.75
+
+randomFromVector :: V.Vector a -> IO a
+randomFromVector vector = do
+ index <- randomRIO (0, V.length vector - 1)
+ return $ vector ! index
+
+{- |
+A genotype is a value which is generated by the genetic algorithm.
+
+The environment is used to specify the problem for which
+we are trying to find the optimal genotype.
+-}
+class Species environment genotype where
+ -- | Randomly generate a new genotype.
+ generate :: environment -> IO genotype
+
+ -- | Randomly mutate a single genotype.
+ mutate :: environment -> genotype -> IO genotype
+
+ -- | Randomly combine two genotypes.
+ crossover :: environment -> genotype -> genotype -> IO genotype
+
+ -- | Score a genotype. Higher numbers are better.
+ fitness :: environment -> genotype -> Double
+
+initialPopulation :: Species e g
+ => e -- ^ Environment
+ -> IO (V.Vector g) -- ^ Population
+initialPopulation environment
+ = V.replicateM numSurvivors (generate environment)
+
+-- | Expand a population by crossovers followed by mutations.
+evolvePopulation :: Species e g
+ => e -- ^ Environment
+ -> V.Vector g -- ^ Survivors from previous generation
+ -> IO (V.Vector g) -- ^ New population
+evolvePopulation environment population = do
+ let randomCrossover = do
+ a <- randomFromVector population
+ b <- randomFromVector population
+ crossover environment a b
+
+ randomMutation chromosome = do
+ r <- randomRIO (0.0, 1.0)
+ if r <= mutationProbability
+ then mutate environment chromosome
+ else return chromosome
+
+ newborns <- V.replicateM numNewborns randomCrossover
+ let nonElites = V.tail population V.++ newborns
+ nonElites' <- V.mapM randomMutation nonElites
+ return $ V.head population `V.cons` nonElites'
+
+selectSurvivors :: Species e g
+ => e -- ^ Environment
+ -> V.Vector g -- ^ Original population
+ -> (Double, V.Vector g) -- ^ Best fitness, survivors
+selectSurvivors environment population =
+ let -- Fitness is stored to avoid calculating it for each comparison.
+ calculateFitness g = (fitness environment g, g)
+ getFitness = fst
+ getGenotype = snd
+ compareFitness = comparing $ Down . fst
+
+ -- Moves k best genotypes to the front, but doesn't sort them further.
+ selectBest k vector = selectBy compareFitness vector k
+
+ selected = V.modify (selectBest 1)
+ $ V.take numSurvivors
+ $ V.modify (selectBest numSurvivors)
+ $ V.map calculateFitness population
+
+ in ( getFitness $ V.head selected
+ , V.map getGenotype selected
+ )
+
+shouldContinue :: [Double] -- ^ Fitness history
+ -> Bool
+shouldContinue (x:y:_) = x /= y
+shouldContinue _ = True
+
+evolutionLoop :: Species e g
+ => e -- ^ Environment
+ -> [Double] -- ^ Fitness history
+ -> V.Vector g -- ^ Survivors from previous generation
+ -> IO (V.Vector g) -- ^ Final population
+evolutionLoop environment history survivors =
+ do
+ population <- evolvePopulation environment survivors
+
+ let (bestFitness, survivors') = selectSurvivors environment population
+ history' = bestFitness : history
+
+ printf "Generation: %3i Fitness: %7.1f\n"
+ (length history') (head history')
+
+ if shouldContinue history'
+ then evolutionLoop environment history' survivors'
+ else return survivors'
+
+-- | Run the genetic algorithm.
+evolve :: Species e g
+ => e -- ^ Environment
+ -> IO g -- ^ Optimal genotype
+evolve environment = do
+ population <- initialPopulation environment
+ survivors <- evolutionLoop environment [] population
+ return $ V.head survivors
diff --git a/palette-generator/Data/Colour.hs b/palette-generator/Data/Colour.hs
new file mode 100644
index 0000000..45dc33d
--- /dev/null
+++ b/palette-generator/Data/Colour.hs
@@ -0,0 +1,70 @@
+module Data.Colour ( LAB(..), RGB(..), deltaE, lab2rgb, rgb2lab ) where
+
+data LAB = LAB { lightness :: Double
+ , channelA :: Double
+ , channelB :: Double
+ }
+
+data RGB = RGB { red :: Double
+ , green :: Double
+ , blue :: Double
+ }
+
+-- Based on https://github.com/antimatter15/rgb-lab/blob/master/color.js
+
+deltaE :: LAB -> LAB -> Double
+deltaE (LAB l1 a1 b1) (LAB l2 a2 b2) =
+ let deltaL = l1 - l2
+ deltaA = a1 - a2
+ deltaB = b1 - b2
+ c1 = sqrt $ a1^2 + b1^2
+ c2 = sqrt $ a2^2 + b2^2
+ deltaC = c1 - c2
+ deltaH = deltaA^2 + deltaB^2 - deltaC^2
+ deltaH' = if deltaH < 0 then 0 else sqrt deltaH
+ sc = 1 + 0.045 * c1
+ sh = 1 + 0.015 * c1
+ deltaCkcsc = deltaC / sc
+ deltaHkhsh = deltaH' / sh
+ i = deltaL^2 + deltaCkcsc^2 + deltaHkhsh^2
+ in if i < 0 then 0 else sqrt i
+
+-- | Convert a 'LAB' colour to a 'RGB' colour
+lab2rgb :: LAB -> RGB
+lab2rgb (LAB l a bx) =
+ let y = (l + 16) / 116
+ x = a / 500 + y
+ z = y - bx / 200
+ x' = 0.95047 * (if x^3 > 0.008856 then x^3 else (x - 16/116) / 7.787)
+ y' = if y^3 > 0.008856 then y^3 else (y - 16/116) / 7.787
+ z' = 1.08883 * (if z^3 > 0.008856 then z^3 else (z - 16/116) / 7.787)
+ r = x' * 3.2406 + y' * (-1.5372) + z' * (-0.4986)
+ g = x' * (-0.9689) + y' * 1.8758 + z' * 0.0415
+ b = x' * 0.0557 + y' * (-0.204) + z' * 1.0570
+ r' = if r > 0.0031308 then 1.055 * r**(1/2.4) - 0.055 else 12.92 * r
+ g' = if g > 0.0031308 then 1.055 * g**(1/2.4) - 0.055 else 12.92 * g
+ b' = if b > 0.0031308 then 1.055 * b**(1/2.4) - 0.055 else 12.92 * b
+ in RGB { red = max 0 (min 1 r') * 255
+ , green = max 0 (min 1 g') * 255
+ , blue = max 0 (min 1 b') * 255
+ }
+
+-- | Convert a 'RGB' colour to a 'LAB' colour
+rgb2lab :: RGB -> LAB
+rgb2lab (RGB r g b) =
+ let r' = r / 255
+ g' = g / 255
+ b' = b / 255
+ r'' = if r' > 0.04045 then ((r' + 0.055) / 1.055)**2.4 else r' / 12.92
+ g'' = if g' > 0.04045 then ((g' + 0.055) / 1.055)**2.4 else g' / 12.92
+ b'' = if b' > 0.04045 then ((b' + 0.055) / 1.055)**2.4 else b' / 12.92
+ x = (r'' * 0.4124 + g'' * 0.3576 + b'' * 0.1805) / 0.95047
+ y = r'' * 0.2126 + g'' * 0.7152 + b'' * 0.0722
+ z = (r'' * 0.0193 + g'' * 0.1192 + b'' * 0.9505) / 1.08883
+ x' = if x > 0.008856 then x**(1/3) else (7.787 * x) + 16/116
+ y' = if y > 0.008856 then y**(1/3) else (7.787 * y) + 16/116
+ z' = if z > 0.008856 then z**(1/3) else (7.787 * z) + 16/116
+ in LAB { lightness = (116 * y') - 16
+ , channelA = 500 * (x' - y')
+ , channelB = 200 * (y' - z')
+ }
diff --git a/palette-generator/Stylix/Main.hs b/palette-generator/Stylix/Main.hs
new file mode 100644
index 0000000..2170d62
--- /dev/null
+++ b/palette-generator/Stylix/Main.hs
@@ -0,0 +1,39 @@
+import Ai.Evolutionary (evolve)
+import Codec.Picture (DynamicImage, convertRGB8, readImage)
+import Data.Colour (lab2rgb)
+import qualified Data.Vector as V
+import Stylix.Output (makeOutputTable)
+import Stylix.Palette ()
+import System.Environment (getArgs)
+import System.Exit (die)
+import System.Random (mkStdGen, setStdGen)
+import Text.JSON (encode)
+
+-- | Load an image file.
+loadImage :: String -- ^ Path to the file
+ -> IO DynamicImage
+loadImage input = either error id <$> readImage input
+
+mainProcess :: (String, String, String) -> IO ()
+mainProcess (polarity, input, output) = do
+ putStrLn $ "Processing " ++ input
+
+ -- Random numbers must be deterministic when running inside Nix.
+ setStdGen $ mkStdGen 0
+
+ image <- loadImage input
+ palette <- evolve (polarity, convertRGB8 image)
+ let outputTable = makeOutputTable $ V.map lab2rgb palette
+
+ writeFile output $ encode outputTable
+ putStrLn $ "Saved to " ++ output
+
+parseArguments :: [String] -> Either String (String, String, String)
+parseArguments [polarity, input, output] = Right (polarity, input, output)
+parseArguments [_, _] = Left "Please specify an output file"
+parseArguments [_] = Left "Please specify an image"
+parseArguments [] = Left "Please specify a polarity: either, light or dark"
+parseArguments _ = Left "Too many arguments"
+
+main :: IO ()
+main = either die mainProcess . parseArguments =<< getArgs
diff --git a/palette-generator/Stylix/Output.hs b/palette-generator/Stylix/Output.hs
new file mode 100644
index 0000000..682d421
--- /dev/null
+++ b/palette-generator/Stylix/Output.hs
@@ -0,0 +1,27 @@
+module Stylix.Output ( makeOutputTable ) where
+
+import Data.Colour (RGB (RGB))
+import qualified Data.Vector as V
+import Data.Word (Word8)
+import Text.JSON (JSObject, toJSObject)
+import Text.Printf (printf)
+
+toHexNum :: Double -> Word8
+toHexNum = truncate
+
+{- |
+Convert a colour to a hexadecimal string.
+
+>>> toHex (RGB 255 255 255)
+"ffffff"
+-}
+toHex :: RGB -> String
+toHex (RGB r g b) = printf "%02x%02x%02x" (toHexNum r) (toHexNum g) (toHexNum b)
+
+-- | Convert a palette to the JSON format expected by Stylix's NixOS modules.
+makeOutputTable :: V.Vector RGB -> JSObject String
+makeOutputTable
+ = toJSObject
+ . V.toList
+ . V.imap (\i c -> (printf "base%02X" i, c))
+ . V.map toHex
diff --git a/palette-generator/Stylix/Palette.hs b/palette-generator/Stylix/Palette.hs
new file mode 100644
index 0000000..1b8b0d7
--- /dev/null
+++ b/palette-generator/Stylix/Palette.hs
@@ -0,0 +1,94 @@
+{-# LANGUAGE FlexibleInstances #-}
+{-# LANGUAGE MultiParamTypeClasses #-}
+
+module Stylix.Palette ( ) where
+
+import Ai.Evolutionary (Species (..))
+import Codec.Picture (Image (imageHeight, imageWidth),
+ PixelRGB8 (PixelRGB8), pixelAt)
+import Data.Colour (LAB (lightness), RGB (RGB), deltaE, rgb2lab)
+import Data.List (delete)
+import Data.Vector ((//))
+import qualified Data.Vector as V
+import System.Random (randomRIO)
+
+-- | Extract the primary scale from a palette.
+primary :: V.Vector a -> V.Vector a
+primary = V.take 8
+
+-- | Extract the accent colours from a palette.
+accent :: V.Vector a -> V.Vector a
+accent = V.drop 8
+
+{- |
+Combine two palettes by taking a colour from the left,
+then the right, then the left, and so on until we have
+taken enough colours for a new palette.
+-}
+alternatingZip :: V.Vector a -> V.Vector a -> V.Vector a
+alternatingZip = V.izipWith (\i a b -> if even i then a else b)
+
+randomFromImage :: Image PixelRGB8 -> IO LAB
+randomFromImage image = do
+ x <- randomRIO (0, imageWidth image - 1)
+ y <- randomRIO (0, imageHeight image - 1)
+ let (PixelRGB8 r g b) = pixelAt image x y
+ color = RGB (fromIntegral r) (fromIntegral g) (fromIntegral b)
+ return $ rgb2lab color
+
+instance Species (String, Image PixelRGB8) (V.Vector LAB) where
+ generate (_, image) = V.replicateM 16 $ randomFromImage image
+
+ crossover _ a b = return $ alternatingZip a b
+
+ mutate (_, image) palette = do
+ index <- randomRIO (0, 15)
+ colour <- randomFromImage image
+ return $ palette // [(index, colour)]
+
+ fitness (polarity, _) palette
+ = realToFrac $ accentDifference - (primarySimilarity/10) - scheme
+ where
+ -- The primary scale should use similar colours, to an extent.
+ primarySimilarity = maximum $ do
+ a <- primary palette
+ b <- primary palette
+ return $ deltaE a b
+
+ -- The accent colours should be as different as possible.
+ accentDifference = minimum $ do
+ index_x <- [0..7]
+ index_y <- delete index_x [0..7]
+ let x = accent palette V.! index_x
+ y = accent palette V.! index_y
+ return $ deltaE x y
+
+ -- Helpers for the function below.
+ lightnesses = V.map lightness palette
+ difference a b = abs $ a - b
+
+ lightnessError primaryScale accentValue
+ -- The primary scale's lightnesses should match the given pattern.
+ = sum (V.zipWith difference primaryScale $ primary lightnesses)
+ -- The accent colours should all have the given lightness.
+ + sum (V.map (difference accentValue) $ accent lightnesses)
+
+ scheme = case polarity of
+ "either" -> min lightScheme darkScheme
+ "light" -> lightScheme
+ "dark" -> darkScheme
+ _ -> error ("Invalid polarity: " ++ polarity)
+
+ {-
+ For light themes, the background is bright and the text is dark.
+ The accent colours are slightly darker.
+ -}
+ lightScheme
+ = lightnessError (V.fromList [90, 70, 55, 35, 25, 10, 5, 5]) 40
+
+ {-
+ For dark themes, the background is dark and the text is bright.
+ The accent colours are slightly brighter.
+ -}
+ darkScheme
+ = lightnessError (V.fromList [10, 30, 45, 65, 75, 90, 95, 95]) 60
diff --git a/palette-generator/default.nix b/palette-generator/default.nix
new file mode 100644
index 0000000..99a7c24
--- /dev/null
+++ b/palette-generator/default.nix
@@ -0,0 +1,42 @@
+{ haskellPackages, stdenvNoCC }:
+
+let
+ ghc = haskellPackages.ghcWithPackages (
+ ps: with ps; [
+ JuicyPixels
+ json
+ random
+ vector-algorithms
+ ]
+ );
+
+ # `nix build .#palette-generator.passthru.docs` and open in a web browser
+ docs = stdenvNoCC.mkDerivation {
+ name = "palette-generator-haddock";
+
+ src = ./.;
+ buildInputs = [ ghc ];
+
+ buildPhase = ''
+ haddock $src/**/*.hs --html --ignore-all-exports --odir $out
+ '';
+ dontInstall = true;
+ dontFixup = true;
+ };
+
+in
+stdenvNoCC.mkDerivation {
+ name = "palette-generator";
+
+ src = ./.;
+ buildInputs = [ ghc ];
+
+ buildPhase = ''
+ ghc -O -threaded -Wall -Wno-type-defaults Stylix/Main.hs
+ '';
+ installPhase = ''
+ install -D Stylix/Main $out/bin/palette-generator
+ '';
+
+ passthru = { inherit docs; };
+}
diff --git a/stylix/autoload.nix b/stylix/autoload.nix
new file mode 100644
index 0000000..c549e42
--- /dev/null
+++ b/stylix/autoload.nix
@@ -0,0 +1,17 @@
+{ lib, inputs }:
+
+# string -> [ path ]
+# List include path for either nixos modules or hm modules
+for:
+builtins.concatLists (
+ lib.mapAttrsToList (
+ path: kind:
+ if kind == "directory" then
+ let
+ file = "${inputs.self}/modules/${path}/${for}.nix";
+ in
+ if builtins.pathExists file then [ file ] else [ ]
+ else
+ [ ]
+ ) (builtins.readDir "${inputs.self}/modules")
+)
diff --git a/stylix/colors.nix b/stylix/colors.nix
deleted file mode 100644
index e84a843..0000000
--- a/stylix/colors.nix
+++ /dev/null
@@ -1,27 +0,0 @@
-{ pkgs, lib, config, ... }:
-
-with lib;
-
-let
- cfg = config.stylix;
-
- # TODO: This Python library should be included in Nixpkgs
- colorgram = with pkgs.python3Packages; buildPythonPackage rec {
- pname = "colorgram.py";
- version = "1.2.0";
- src = fetchPypi {
- inherit pname version;
- sha256 = "1gzxgcmg3ndra2j4dg73x8q9dw6b0akj474gxyyhfwnyz6jncxz7";
- };
- propagatedBuildInputs = [ pillow ];
- };
- colorgramPython = pkgs.python3.withPackages (ps: [ colorgram ]);
-
- # Pass the wallpaper to ./colors.py and return a JSON file containing the
- # generated colorscheme
- colorsJSON = pkgs.runCommand "stylix-colors" {}
- "${colorgramPython}/bin/python ${./colors.py} ${cfg.image} > $out";
-
-in {
- config.lib.stylix.colors = importJSON colorsJSON;
-}
diff --git a/stylix/colors.py b/stylix/colors.py
deleted file mode 100644
index 56cab0b..0000000
--- a/stylix/colors.py
+++ /dev/null
@@ -1,85 +0,0 @@
-import json
-import sys
-import colorgram
-import colorsys
-
-
-# Select 9 colors from the image passed on the command line
-colors = colorgram.extract(sys.argv[1], 9)
-
-
-# Extract the most dominant color to use as the background
-colors.sort(key=lambda c: c.proportion)
-dominant_color = colors.pop(0)
-
-# Decide whether to generate a light or dark scheme based
-# on the lightness of the dominant color
-if dominant_color.hsl.l >= 128:
- def scale(i):
- scale = 0.8 - (0.1 * i)
- return scale * 255
-
- def clamp(l):
- return min(l, 100)
-else:
- def scale(i):
- scale = 0.1 + (0.1 * i)
- return scale * 255
-
- def clamp(l):
- return max(l, 155)
-
-
-def int_to_base(i):
- return "base{0:02X}".format(i)
-
-scheme = {}
-
-# base00 to base07 use the dominant color's hue and saturation,
-# lightness is a linear scale
-for i in range(8):
- scheme[int_to_base(i)] = (
- dominant_color.hsl.h,
- dominant_color.hsl.s,
- scale(i),
- )
-
-# base08 to base0A use the remaining 8 colors from the image,
-# with their lightness clamped to enforce adequate contrast
-colors.sort(key=lambda c: c.hsl.h) # sort by hue
-for i in range(8, 16):
- color = colors[i-8]
- scheme[int_to_base(i)] = (
- color.hsl.h,
- color.hsl.s,
- clamp(color.hsl.l),
- )
-
-
-data = {}
-
-for key, color in scheme.items():
- r, g, b = colorsys.hls_to_rgb(
- # Function wants HLS, stored as HSL
- color[0] / 255,
- color[2] / 255,
- color[1] / 255,
- )
- data[key + "-dec-r"] = r
- data[key + "-dec-g"] = g
- data[key + "-dec-b"] = b
- data[key + "-rgb-r"] = r * 255
- data[key + "-rgb-g"] = g * 255
- data[key + "-rgb-b"] = b * 255
-
- hex_color = "{0:02x}{1:02x}{2:02x}".format(
- round(r * 255),
- round(g * 255),
- round(b * 255),
- )
- data[key + "-hex"] = hex_color
- data[key + "-hex-r"] = hex_color[0:2]
- data[key + "-hex-g"] = hex_color[2:4]
- data[key + "-hex-b"] = hex_color[4:6]
-
-json.dump(data, sys.stdout)
diff --git a/stylix/cursor.nix b/stylix/cursor.nix
new file mode 100644
index 0000000..412cf67
--- /dev/null
+++ b/stylix/cursor.nix
@@ -0,0 +1,21 @@
+{ pkgs, lib, ... }:
+
+{
+ options.stylix.cursor = {
+ name = lib.mkOption {
+ description = "The cursor name within the package.";
+ type = lib.types.str;
+ default = "Vanilla-DMZ";
+ };
+ package = lib.mkOption {
+ description = "Package providing the cursor theme.";
+ type = lib.types.package;
+ default = pkgs.vanilla-dmz;
+ };
+ size = lib.mkOption {
+ description = "The cursor size.";
+ type = lib.types.int;
+ default = 32;
+ };
+ };
+}
diff --git a/stylix/darwin/default.nix b/stylix/darwin/default.nix
new file mode 100644
index 0000000..6a85d5e
--- /dev/null
+++ b/stylix/darwin/default.nix
@@ -0,0 +1,22 @@
+inputs:
+{
+ palette-generator,
+ base16,
+ homeManagerModule,
+}:
+{ lib, ... }:
+
+let
+ autoload = import ../autoload.nix { inherit lib inputs; } "darwin";
+in
+{
+ imports = [
+ ../pixel.nix
+ ../target.nix
+ ../opacity.nix
+ ./fonts.nix
+ (import ./palette.nix { inherit palette-generator base16; })
+ (import ../templates.nix inputs)
+ (import ../home-manager-integration.nix homeManagerModule)
+ ] ++ autoload;
+}
diff --git a/stylix/darwin/fonts.nix b/stylix/darwin/fonts.nix
new file mode 100644
index 0000000..ed72158
--- /dev/null
+++ b/stylix/darwin/fonts.nix
@@ -0,0 +1,11 @@
+{ config, lib, ... }:
+
+let
+ cfg = config.stylix.fonts;
+in
+{
+ imports = [ ../fonts.nix ];
+ config.fonts = lib.mkIf config.stylix.enable {
+ inherit (cfg) packages;
+ };
+}
diff --git a/stylix/darwin/palette.nix b/stylix/darwin/palette.nix
new file mode 100644
index 0000000..23c299f
--- /dev/null
+++ b/stylix/darwin/palette.nix
@@ -0,0 +1,10 @@
+args:
+{ config, lib, ... }:
+
+{
+ imports = [ (import ../palette.nix args) ];
+
+ config = lib.mkIf config.stylix.enable {
+ environment.etc = config.stylix.generated.fileTree;
+ };
+}
diff --git a/stylix/default.nix b/stylix/default.nix
deleted file mode 100644
index 90fea24..0000000
--- a/stylix/default.nix
+++ /dev/null
@@ -1,16 +0,0 @@
-{ lib, ... }:
-
-with lib;
-
-{
- imports = [
- ./colors.nix
- ./fonts.nix
- ./home-manager.nix
- ];
-
- options.stylix.image = mkOption {
- type = types.package;
- description = "Wallpaper image.";
- };
-}
diff --git a/stylix/fonts.nix b/stylix/fonts.nix
index 1b5b075..d2b63d7 100644
--- a/stylix/fonts.nix
+++ b/stylix/fonts.nix
@@ -1,25 +1,31 @@
-{ pkgs, config, lib, ... }:
-
-with lib;
+{
+ pkgs,
+ config,
+ lib,
+ ...
+}:
let
cfg = config.stylix.fonts;
- fontType = types.submodule { options = {
- package = mkOption {
- description = "Package providing the font.";
- type = types.package;
- };
+ fontType = lib.types.submodule {
+ options = {
+ package = lib.mkOption {
+ description = "Package providing the font.";
+ type = lib.types.package;
+ };
- name = mkOption {
- description = "Name of the font within the package.";
- type = types.str;
+ name = lib.mkOption {
+ description = "Name of the font within the package.";
+ type = lib.types.str;
+ };
};
- }; };
+ };
-in {
+in
+{
options.stylix.fonts = {
- serif = mkOption {
+ serif = lib.mkOption {
description = "Serif font.";
type = fontType;
default = {
@@ -28,7 +34,7 @@ in {
};
};
- sansSerif = mkOption {
+ sansSerif = lib.mkOption {
description = "Sans-serif font.";
type = fontType;
default = {
@@ -37,7 +43,7 @@ in {
};
};
- monospace = mkOption {
+ monospace = lib.mkOption {
description = "Monospace font.";
type = fontType;
default = {
@@ -46,7 +52,7 @@ in {
};
};
- emoji = mkOption {
+ emoji = lib.mkOption {
description = "Emoji font.";
type = fontType;
default = {
@@ -54,21 +60,58 @@ in {
name = "Noto Color Emoji";
};
};
+
+ sizes = {
+ desktop = lib.mkOption {
+ description = ''
+ The font size (in pt) used in window titles/bars/widgets elements of
+ the desktop.
+ '';
+ type = with lib.types; (either ints.unsigned float);
+ default = 10;
+ };
+
+ applications = lib.mkOption {
+ description = ''
+ The font size (in pt) used by applications.
+ '';
+ type = with lib.types; (either ints.unsigned float);
+ default = 12;
+ };
+
+ terminal = lib.mkOption {
+ description = ''
+ The font size (in pt) for terminals/text editors.
+ '';
+ type = with lib.types; (either ints.unsigned float);
+ default = cfg.sizes.applications;
+ };
+
+ popups = lib.mkOption {
+ description = ''
+ The font size (in pt) for notifications/popups and in general overlay
+ elements of the desktop.
+ '';
+ type = with lib.types; (either ints.unsigned float);
+ default = cfg.sizes.desktop;
+ };
+ };
+
+ packages = lib.mkOption {
+ description = ''
+ A list of all the font packages that will be installed.
+ '';
+ type = lib.types.listOf lib.types.package;
+ readOnly = true;
+ };
};
- config.fonts = {
- fonts = [
+ config = lib.mkIf config.stylix.enable {
+ stylix.fonts.packages = [
cfg.monospace.package
cfg.serif.package
cfg.sansSerif.package
cfg.emoji.package
];
-
- fontconfig.defaultFonts = {
- monospace = [ cfg.monospace.name ];
- serif = [ cfg.serif.name ];
- sansSerif = [ cfg.sansSerif.name ];
- emoji = [ cfg.emoji.name ];
- };
};
}
diff --git a/stylix/hm/cursor.nix b/stylix/hm/cursor.nix
new file mode 100644
index 0000000..a821742
--- /dev/null
+++ b/stylix/hm/cursor.nix
@@ -0,0 +1,22 @@
+{
+ config,
+ lib,
+ pkgs,
+ ...
+}:
+
+let
+ cfg = config.stylix.cursor;
+
+in
+{
+ imports = [ ../cursor.nix ];
+
+ config = lib.mkIf (config.stylix.enable && pkgs.stdenv.hostPlatform.isLinux) {
+ home.pointerCursor = {
+ inherit (cfg) name package size;
+ x11.enable = true;
+ gtk.enable = true;
+ };
+ };
+}
diff --git a/stylix/hm/default.nix b/stylix/hm/default.nix
new file mode 100644
index 0000000..d160a03
--- /dev/null
+++ b/stylix/hm/default.nix
@@ -0,0 +1,19 @@
+inputs:
+{ palette-generator, base16 }:
+{ lib, ... }:
+
+let
+ autoload = import ../autoload.nix { inherit lib inputs; } "hm";
+in
+{
+ imports = [
+ ../pixel.nix
+ ../target.nix
+ ../opacity.nix
+ ./cursor.nix
+ ./fonts.nix
+ ./icon.nix
+ (import ./palette.nix { inherit palette-generator base16; })
+ (import ../templates.nix inputs)
+ ] ++ autoload;
+}
diff --git a/stylix/hm/fonts.nix b/stylix/hm/fonts.nix
new file mode 100644
index 0000000..a7b46e6
--- /dev/null
+++ b/stylix/hm/fonts.nix
@@ -0,0 +1,12 @@
+{ config, lib, ... }:
+
+let
+ cfg = config.stylix.fonts;
+in
+{
+ imports = [ ../fonts.nix ];
+ config = lib.mkIf config.stylix.enable {
+ fonts.fontconfig.enable = true;
+ home.packages = cfg.packages;
+ };
+}
diff --git a/stylix/hm/icon.nix b/stylix/hm/icon.nix
new file mode 100644
index 0000000..e47e75d
--- /dev/null
+++ b/stylix/hm/icon.nix
@@ -0,0 +1,28 @@
+{ config, lib, ... }:
+
+let
+ cfg = config.stylix.iconTheme;
+ inherit (config.stylix) polarity;
+in
+{
+ imports = [ ../icon.nix ];
+ config = lib.mkIf (config.stylix.enable && cfg.enable) {
+ gtk = {
+ iconTheme = {
+ inherit (cfg) package;
+ name = builtins.head (
+ lib.filter (x: null != x) [
+ (
+ {
+ inherit (cfg) dark light;
+ }
+ ."${polarity}" or null
+ )
+ cfg.dark
+ cfg.light
+ ]
+ );
+ };
+ };
+ };
+}
diff --git a/stylix/hm/palette.nix b/stylix/hm/palette.nix
new file mode 100644
index 0000000..cb8d5b3
--- /dev/null
+++ b/stylix/hm/palette.nix
@@ -0,0 +1,10 @@
+args:
+{ config, lib, ... }:
+
+{
+ imports = [ (import ../palette.nix args) ];
+
+ config = lib.mkIf config.stylix.enable {
+ xdg.configFile = config.stylix.generated.fileTree;
+ };
+}
diff --git a/stylix/home-manager-integration.nix b/stylix/home-manager-integration.nix
new file mode 100644
index 0000000..eb4a3bb
--- /dev/null
+++ b/stylix/home-manager-integration.nix
@@ -0,0 +1,216 @@
+homeManagerModule:
+{
+ lib,
+ config,
+ options,
+ ...
+}:
+
+let
+ copyModules =
+ builtins.map
+ (
+ {
+ path,
+ condition ? lib.const true,
+ }:
+ { config, osConfig, ... }:
+ lib.mkIf (condition config) (
+ lib.setAttrByPath path (lib.mkDefault (lib.getAttrFromPath path osConfig))
+ )
+ )
+ [
+ {
+ path = [
+ "stylix"
+ "autoEnable"
+ ];
+ }
+ {
+ path = [
+ "stylix"
+ "base16Scheme"
+ ];
+ condition = homeConfig: config.stylix.image == homeConfig.stylix.image;
+ }
+ {
+ path = [
+ "stylix"
+ "cursor"
+ "name"
+ ];
+ }
+ {
+ path = [
+ "stylix"
+ "cursor"
+ "package"
+ ];
+ }
+ {
+ path = [
+ "stylix"
+ "cursor"
+ "size"
+ ];
+ }
+ {
+ path = [
+ "stylix"
+ "enable"
+ ];
+ }
+ {
+ path = [
+ "stylix"
+ "fonts"
+ "serif"
+ ];
+ }
+ {
+ path = [
+ "stylix"
+ "fonts"
+ "sansSerif"
+ ];
+ }
+ {
+ path = [
+ "stylix"
+ "fonts"
+ "monospace"
+ ];
+ }
+ {
+ path = [
+ "stylix"
+ "fonts"
+ "emoji"
+ ];
+ }
+ {
+ path = [
+ "stylix"
+ "fonts"
+ "sizes"
+ "desktop"
+ ];
+ }
+ {
+ path = [
+ "stylix"
+ "fonts"
+ "sizes"
+ "applications"
+ ];
+ }
+ {
+ path = [
+ "stylix"
+ "fonts"
+ "sizes"
+ "terminal"
+ ];
+ }
+ {
+ path = [
+ "stylix"
+ "fonts"
+ "sizes"
+ "popups"
+ ];
+ }
+ {
+ path = [
+ "stylix"
+ "image"
+ ];
+ }
+ {
+ path = [
+ "stylix"
+ "imageScalingMode"
+ ];
+ }
+ {
+ path = [
+ "stylix"
+ "opacity"
+ "desktop"
+ ];
+ }
+ {
+ path = [
+ "stylix"
+ "opacity"
+ "applications"
+ ];
+ }
+ {
+ path = [
+ "stylix"
+ "opacity"
+ "terminal"
+ ];
+ }
+ {
+ path = [
+ "stylix"
+ "opacity"
+ "popups"
+ ];
+ }
+ {
+ path = [
+ "stylix"
+ "override"
+ ];
+ condition =
+ homeConfig: config.stylix.base16Scheme == homeConfig.stylix.base16Scheme;
+ }
+ {
+ path = [
+ "stylix"
+ "polarity"
+ ];
+ }
+ ];
+
+in
+{
+ options.stylix.homeManagerIntegration = {
+ followSystem = lib.mkOption {
+ description = ''
+ When this option is `true`, Home Manager configurations will follow
+ the NixOS configuration by default, rather than using the standard
+ default settings.
+
+ This only applies to Home Manager configurations managed by
+ [`stylix.homeManagerIntegration.autoImport`](#stylixhomemanagerintegrationautoimport).
+ '';
+ type = lib.types.bool;
+ default = true;
+ example = false;
+ };
+
+ autoImport = lib.mkOption {
+ description = ''
+ Whether to import Stylix automatically for every Home Manager user.
+
+ This only works if you are using `home-manager.users.«name»` within
+ your NixOS configuration, rather than running Home Manager independently.
+ '';
+ type = lib.types.bool;
+ default = true;
+ example = false;
+ };
+ };
+
+ config = lib.optionalAttrs (options ? home-manager) (
+ lib.mkIf config.stylix.homeManagerIntegration.autoImport {
+ home-manager.sharedModules =
+ [ homeManagerModule ]
+ ++ (lib.optionals config.stylix.homeManagerIntegration.followSystem copyModules);
+ }
+ );
+}
diff --git a/stylix/home-manager.nix b/stylix/home-manager.nix
deleted file mode 100644
index 2b89276..0000000
--- a/stylix/home-manager.nix
+++ /dev/null
@@ -1,25 +0,0 @@
-{ lib, config, ... }:
-
-with lib;
-
-let
- cfg = config.stylix;
-
-in {
- options.stylix = {
- homeManagerUsers = mkOption {
- type = types.listOf types.str;
- description = "Users for which to enable Home Manager integration.";
- default = [];
- };
-
- homeModule = mkOption {
- internal = true;
- description = "Home Manager module to apply for all users.";
- };
- };
-
- config = {
- home-manager.users = genAttrs cfg.homeManagerUsers (user: cfg.homeModule);
- };
-}
diff --git a/stylix/icon.nix b/stylix/icon.nix
new file mode 100644
index 0000000..cb7b8db
--- /dev/null
+++ b/stylix/icon.nix
@@ -0,0 +1,26 @@
+{ lib, ... }:
+
+{
+ options.stylix.iconTheme = {
+ enable = lib.mkOption {
+ description = "enable/disable icon theming.";
+ type = lib.types.bool;
+ default = false;
+ };
+ package = lib.mkOption {
+ description = "Package providing the icon theme.";
+ type = lib.types.nullOr lib.types.package;
+ default = null;
+ };
+ light = lib.mkOption {
+ description = "Light icon theme name.";
+ type = lib.types.nullOr lib.types.str;
+ default = null;
+ };
+ dark = lib.mkOption {
+ description = "Dark icon theme name.";
+ type = lib.types.nullOr lib.types.str;
+ default = null;
+ };
+ };
+}
diff --git a/stylix/nixos/cursor.nix b/stylix/nixos/cursor.nix
new file mode 100644
index 0000000..576ad54
--- /dev/null
+++ b/stylix/nixos/cursor.nix
@@ -0,0 +1,11 @@
+{ config, lib, ... }:
+
+let
+ cfg = config.stylix.cursor;
+in
+{
+ imports = [ ../cursor.nix ];
+ config = lib.mkIf config.stylix.enable {
+ environment.variables.XCURSOR_SIZE = toString cfg.size;
+ };
+}
diff --git a/stylix/nixos/default.nix b/stylix/nixos/default.nix
new file mode 100644
index 0000000..49046fe
--- /dev/null
+++ b/stylix/nixos/default.nix
@@ -0,0 +1,23 @@
+inputs:
+{
+ palette-generator,
+ base16,
+ homeManagerModule,
+}:
+{ lib, ... }:
+
+let
+ autoload = import ../autoload.nix { inherit lib inputs; } "nixos";
+in
+{
+ imports = [
+ ../pixel.nix
+ ../target.nix
+ ../opacity.nix
+ ./cursor.nix
+ ./fonts.nix
+ (import ./palette.nix { inherit palette-generator base16; })
+ (import ../templates.nix inputs)
+ (import ../home-manager-integration.nix homeManagerModule)
+ ] ++ autoload;
+}
diff --git a/stylix/nixos/fonts.nix b/stylix/nixos/fonts.nix
new file mode 100644
index 0000000..571a527
--- /dev/null
+++ b/stylix/nixos/fonts.nix
@@ -0,0 +1,18 @@
+{ config, lib, ... }:
+
+let
+ cfg = config.stylix.fonts;
+in
+{
+ imports = [ ../fonts.nix ];
+ config.fonts = lib.mkIf config.stylix.enable {
+ inherit (cfg) packages;
+
+ fontconfig.defaultFonts = {
+ monospace = [ cfg.monospace.name ];
+ serif = [ cfg.serif.name ];
+ sansSerif = [ cfg.sansSerif.name ];
+ emoji = [ cfg.emoji.name ];
+ };
+ };
+}
diff --git a/stylix/nixos/palette.nix b/stylix/nixos/palette.nix
new file mode 100644
index 0000000..23c299f
--- /dev/null
+++ b/stylix/nixos/palette.nix
@@ -0,0 +1,10 @@
+args:
+{ config, lib, ... }:
+
+{
+ imports = [ (import ../palette.nix args) ];
+
+ config = lib.mkIf config.stylix.enable {
+ environment.etc = config.stylix.generated.fileTree;
+ };
+}
diff --git a/stylix/opacity.nix b/stylix/opacity.nix
new file mode 100644
index 0000000..5fe4871
--- /dev/null
+++ b/stylix/opacity.nix
@@ -0,0 +1,26 @@
+{ lib, ... }:
+
+{
+ options.stylix.opacity = {
+ desktop = lib.mkOption {
+ description = "The opacity of the windows of bars/widgets, the amount of applications supported is currently limited";
+ type = lib.types.float;
+ default = 1.0;
+ };
+ applications = lib.mkOption {
+ description = "The opacity of the windows of applications, the amount of applications supported is currently limited";
+ type = lib.types.float;
+ default = 1.0;
+ };
+ terminal = lib.mkOption {
+ description = "The opacity of the windows of terminals, this works across all terminals supported by stylix";
+ type = lib.types.float;
+ default = 1.0;
+ };
+ popups = lib.mkOption {
+ description = "The opacity of the windows of notifications/popups, the amount of applications supported is currently limited";
+ type = lib.types.float;
+ default = 1.0;
+ };
+ };
+}
diff --git a/stylix/palette.html.mustache b/stylix/palette.html.mustache
new file mode 100644
index 0000000..778ca74
--- /dev/null
+++ b/stylix/palette.html.mustache
@@ -0,0 +1,68 @@
+
+
+
+
+
+ Primary colors
+
+
00
+
01
+
02
+
03
+
04
+
05
+
06
+
07
+
+
+ Accents
+
+
08
+
09
+
0A
+
0B
+
0C
+
0D
+
0E
+
0F
+
+
+ Documentation
+ Each color should be used as described in this table.
+ See the Stylix documentation for how to apply these colors on NixOS.
+
+
diff --git a/stylix/palette.json.mustache b/stylix/palette.json.mustache
new file mode 100644
index 0000000..e8dde34
--- /dev/null
+++ b/stylix/palette.json.mustache
@@ -0,0 +1,21 @@
+{
+ "base00": "{{{base00}}}",
+ "base01": "{{{base01}}}",
+ "base02": "{{{base02}}}",
+ "base03": "{{{base03}}}",
+ "base04": "{{{base04}}}",
+ "base05": "{{{base05}}}",
+ "base06": "{{{base06}}}",
+ "base07": "{{{base07}}}",
+ "base08": "{{{base08}}}",
+ "base09": "{{{base09}}}",
+ "base0A": "{{{base0A}}}",
+ "base0B": "{{{base0B}}}",
+ "base0C": "{{{base0C}}}",
+ "base0D": "{{{base0D}}}",
+ "base0E": "{{{base0E}}}",
+ "base0F": "{{{base0F}}}",
+ "scheme": "Stylix",
+ "author": "Stylix",
+ "slug": "stylix"
+}
diff --git a/stylix/palette.nix b/stylix/palette.nix
new file mode 100644
index 0000000..86518b7
--- /dev/null
+++ b/stylix/palette.nix
@@ -0,0 +1,180 @@
+{ palette-generator, base16 }:
+{
+ pkgs,
+ lib,
+ config,
+ ...
+}:
+
+let
+ cfg = config.stylix;
+
+ paletteJSON =
+ let
+ generatedJSON = pkgs.runCommand "palette.json" { } ''
+ ${palette-generator}/bin/palette-generator \
+ "${cfg.polarity}" \
+ ${lib.escapeShellArg "${cfg.image}"} \
+ "$out"
+ '';
+ palette = lib.importJSON generatedJSON;
+ scheme = base16.mkSchemeAttrs palette;
+ json = scheme {
+ template = ./palette.json.mustache;
+ extension = ".json";
+ };
+ in
+ json;
+ generatedScheme = lib.importJSON paletteJSON;
+
+in
+{
+ options.stylix = {
+ polarity = lib.mkOption {
+ type = lib.types.enum [
+ "either"
+ "light"
+ "dark"
+ ];
+ default = "either";
+ description = ''
+ Use this option to force a light or dark theme.
+
+ By default we will select whichever is ranked better by the genetic
+ algorithm. This aims to get good contrast between the foreground and
+ background, as well as some variety in the highlight colours.
+ '';
+ };
+
+ image = lib.mkOption {
+ type = with lib.types; coercedTo package toString path;
+ description = ''
+ Wallpaper image.
+
+ This is set as the background of your desktop environment, if possible,
+ and used to generate a colour scheme if you don't set one manually.
+ '';
+ };
+
+ imageScalingMode = lib.mkOption {
+ type = lib.types.enum [
+ "stretch"
+ "fill"
+ "fit"
+ "center"
+ "tile"
+ ];
+ default = "fill";
+ description = ''
+ Scaling mode for the wallpaper image.
+
+ `stretch`
+ : Stretch the image to cover the screen.
+
+ `fill`
+ : Scale the image to fill the screen, potentially cropping it.
+
+ `fit`
+ : Scale the image to fit the screen without being cropped.
+
+ `center`
+ : Center the image without resizing it.
+
+ `tile`
+ : Tile the image to cover the screen.
+ '';
+ };
+
+ generated = {
+ json = lib.mkOption {
+ type = lib.types.path;
+ description = "The result of palette-generator.";
+ readOnly = true;
+ internal = true;
+ default = paletteJSON;
+ };
+
+ palette = lib.mkOption {
+ type = lib.types.attrs;
+ description = "The imported json";
+ readOnly = true;
+ internal = true;
+ default = generatedScheme;
+ };
+
+ fileTree = lib.mkOption {
+ type = lib.types.raw;
+ description = "The files storing the palettes in json and html.";
+ readOnly = true;
+ internal = true;
+ };
+ };
+
+ base16Scheme = lib.mkOption {
+ description = ''
+ A scheme following the base16 standard.
+
+ This can be a path to a file, a string of YAML, or an attribute set.
+ '';
+ type =
+ with lib.types;
+ oneOf [
+ path
+ lines
+ attrs
+ ];
+ default = generatedScheme;
+ defaultText = lib.literalMD ''
+ The colors used in the theming.
+
+ Those are automatically selected from the background image by default,
+ but could be overridden manually.
+ '';
+ };
+
+ override = lib.mkOption {
+ description = ''
+ An override that will be applied to stylix.base16Scheme when generating
+ config.lib.stylix.colors.
+
+ Takes anything that a scheme generated by base16nix can take as argument
+ to override.
+ '';
+ type = lib.types.attrs;
+ default = { };
+ };
+ };
+
+ config = {
+ # This attrset can be used like a function too, see
+ # https://github.com/SenchoPens/base16.nix/blob/b390e87cd404e65ab4d786666351f1292e89162a/README.md#theme-step-22
+ lib.stylix.colors = (base16.mkSchemeAttrs cfg.base16Scheme).override cfg.override;
+ lib.stylix.scheme = base16.mkSchemeAttrs cfg.base16Scheme;
+
+ stylix.generated.fileTree = {
+ # Making palette.json part of the system closure will protect it from
+ # garbage collection, so future configurations can be evaluated without
+ # having to generate the palette again. The generator is not kept, only
+ # the palette which came from it, so this uses very little disk space.
+ # The extra indirection should prevent the palette generator from running
+ # when the theme is manually specified. generated.json is necessary in
+ # the presence of overrides.
+ "stylix/generated.json".source = config.lib.stylix.scheme {
+ template = ./palette.json.mustache;
+ extension = ".json";
+ };
+
+ "stylix/palette.json".source = config.lib.stylix.colors {
+ template = ./palette.json.mustache;
+ extension = ".json";
+ };
+
+ # We also provide a HTML version which is useful for viewing the colors
+ # during development.
+ "stylix/palette.html".source = config.lib.stylix.colors {
+ template = ./palette.html.mustache;
+ extension = ".html";
+ };
+ };
+ };
+}
diff --git a/stylix/pixel.nix b/stylix/pixel.nix
new file mode 100644
index 0000000..212933f
--- /dev/null
+++ b/stylix/pixel.nix
@@ -0,0 +1,10 @@
+{ pkgs, config, ... }:
+
+{
+ # Generate a PNG image containing a named color
+ config.lib.stylix.pixel =
+ color:
+ pkgs.runCommand "${color}-pixel.png" {
+ color = config.lib.stylix.colors.withHashtag.${color};
+ } "${pkgs.imagemagick}/bin/convert xc:$color png32:$out";
+}
diff --git a/stylix/target.nix b/stylix/target.nix
new file mode 100644
index 0000000..a3d5056
--- /dev/null
+++ b/stylix/target.nix
@@ -0,0 +1,47 @@
+{ config, lib, ... }:
+
+{
+ options.stylix = {
+ enable = lib.mkOption {
+ description = ''
+ Whether to enable Stylix.
+
+ When this is `false`, all theming is disabled and all other options
+ are ignored.
+ '';
+ type = lib.types.bool;
+ default = false;
+ example = true;
+ };
+
+ autoEnable = lib.mkOption {
+ description = ''
+ Whether to enable targets by default.
+
+ When this is `false`, all targets are disabled unless explicitly enabled.
+
+ When this is `true`, most targets are enabled by default. A small number
+ remain off by default, because they require further manual setup, or
+ they are only applicable in specific circumstances which cannot be
+ detected automatically.
+ '';
+ type = lib.types.bool;
+ default = true;
+ example = false;
+ };
+ };
+
+ config.lib.stylix.mkEnableTarget =
+ let
+ cfg = config.stylix;
+ in
+ humanName: autoEnable:
+ lib.mkEnableOption "theming for ${humanName}"
+ // {
+ default = cfg.enable && cfg.autoEnable && autoEnable;
+ example = !autoEnable;
+ }
+ // lib.optionalAttrs autoEnable {
+ defaultText = lib.literalMD "same as [`stylix.autoEnable`](#stylixautoenable)";
+ };
+}
diff --git a/stylix/templates.nix b/stylix/templates.nix
new file mode 100644
index 0000000..7c779d4
--- /dev/null
+++ b/stylix/templates.nix
@@ -0,0 +1,13 @@
+inputs: {
+ config.lib.stylix.templates = {
+ inherit (inputs)
+ base16-fish
+ base16-helix
+ base16-vim
+ gnome-shell
+ tinted-foot
+ tinted-kitty
+ tinted-tmux
+ ;
+ };
+}
diff --git a/stylix/testbed.nix b/stylix/testbed.nix
new file mode 100644
index 0000000..a0a710e
--- /dev/null
+++ b/stylix/testbed.nix
@@ -0,0 +1,176 @@
+{
+ pkgs,
+ inputs,
+ lib,
+ ...
+}:
+
+let
+ username = "guest";
+
+ commonModule =
+ { config, ... }:
+ {
+ users.users.${username} = {
+ description = "Guest";
+ hashedPassword = "";
+ isNormalUser = true;
+ extraGroups = [ "wheel" ];
+ };
+
+ security.sudo.wheelNeedsPassword = false;
+
+ # The state version can safely track the latest release because the disk
+ # image is ephemeral.
+ system.stateVersion = config.system.nixos.release;
+ home-manager.users.${username}.home.stateVersion = config.system.nixos.release;
+
+ virtualisation.vmVariant.virtualisation = {
+ # This is a maximum limit; the VM should still work if the host has fewer cores.
+ cores = 4;
+ memorySize = lib.mkDefault 2048;
+ };
+ };
+
+ applicationModule =
+ { config, lib, ... }:
+ {
+ options.stylix.testbed.application = {
+ enable = lib.mkOption {
+ type = lib.types.bool;
+ default = false;
+ description = ''
+ Whether to enable a standard configuration for testing individual
+ applications.
+
+ This will automatically log in as the `${username}` user, then launch
+ the application from its desktop entry.
+
+ This is currently based on GNOME, but the specific desktop environment
+ used may change in the future.
+ '';
+ };
+
+ name = lib.mkOption {
+ type = lib.types.str;
+ description = ''
+ The name of the desktop entry for the application, without the
+ `.desktop` extension.
+ '';
+ };
+
+ package = lib.mkOption {
+ type = lib.types.package;
+ description = ''
+ The application being tested.
+ '';
+ };
+ };
+
+ config = lib.mkIf config.stylix.testbed.application.enable {
+ services.xserver = {
+ enable = true;
+ displayManager.gdm.enable = true;
+ desktopManager.gnome.enable = true;
+ };
+
+ services.displayManager.autoLogin = {
+ enable = true;
+ user = username;
+ };
+
+ # Disable the GNOME tutorial which pops up on first login.
+ environment.gnome.excludePackages = [ pkgs.gnome-tour ];
+
+ environment.systemPackages = [
+ (pkgs.makeAutostartItem {
+ inherit (config.stylix.testbed.application) name package;
+ })
+ ];
+ };
+ };
+
+ autoload = builtins.concatLists (
+ lib.mapAttrsToList (
+ name: _:
+ let
+ testbed = {
+ inherit name;
+ module = "${inputs.self}/modules/${name}/testbed.nix";
+ };
+ in
+ lib.optional (builtins.pathExists testbed.module) testbed
+ ) (builtins.readDir "${inputs.self}/modules")
+ );
+
+ makeTestbed =
+ testbed: stylix:
+ let
+ name = "testbed-${testbed.name}-${stylix.polarity}";
+
+ system = lib.nixosSystem {
+ inherit (pkgs) system;
+
+ modules = [
+ commonModule
+ applicationModule
+ inputs.self.nixosModules.stylix
+ inputs.home-manager.nixosModules.home-manager
+ testbed.module
+
+ {
+ inherit stylix;
+ system.name = name;
+ }
+ ];
+ };
+
+ script = pkgs.writeShellApplication {
+ inherit name;
+ text = ''
+ cleanup() {
+ if rm --recursive "$directory"; then
+ printf '%s\n' 'Virtualisation disk image removed.'
+ fi
+ }
+
+ # We create a temporary directory rather than a temporary file, since
+ # temporary files are created empty and are not valid disk images.
+ directory="$(mktemp --directory)"
+ trap cleanup EXIT
+
+ NIX_DISK_IMAGE="$directory/nixos.qcow2" \
+ ${lib.getExe system.config.system.build.vm}
+ '';
+ };
+ in
+ lib.nameValuePair name script;
+
+ # This generates a copy of each testbed for each of the following themes.
+ makeTestbeds =
+ testbed:
+ map (makeTestbed testbed) [
+ {
+ enable = true;
+ image = pkgs.fetchurl {
+ name = "three-bicycles.jpg";
+ url = "https://unsplash.com/photos/hwLAI5lRhdM/download?ixid=M3wxMjA3fDB8MXxhbGx8fHx8fHx8fHwxNzE2MzYxNDcwfA&force=true";
+ hash = "sha256-S0MumuBGJulUekoGI2oZfUa/50Jw0ZzkqDDu1nRkFUA=";
+ };
+ base16Scheme = "${pkgs.base16-schemes}/share/themes/catppuccin-latte.yaml";
+ polarity = "light";
+ }
+ {
+ enable = true;
+ image = pkgs.fetchurl {
+ name = "mountains.jpg";
+ url = "https://unsplash.com/photos/ZqLeQDjY6fY/download?ixid=M3wxMjA3fDB8MXxhbGx8fHx8fHx8fHwxNzE2MzY1NDY4fA&force=true";
+ hash = "sha256-Dm/0nKiTFOzNtSiARnVg7zM0J1o+EuIdUQ3OAuasM58=";
+ };
+ base16Scheme = "${pkgs.base16-schemes}/share/themes/catppuccin-macchiato.yaml";
+ polarity = "dark";
+ }
+ ];
+
+in
+lib.listToAttrs (lib.flatten (map makeTestbeds autoload))