feat(desktop): theme the graphical layer Nord with Stylix (task 0022) #14
@@ -13,8 +13,34 @@ The theming is reversible per target, so individual surfaces can migrate toward
|
||||
|
||||
## Acceptance criteria
|
||||
|
||||
- [ ] Stylix is a flake input, wired into the host build.
|
||||
- [ ] A desktop theming module resolves a single Nord base16 scheme and applies it to GTK, Qt, cursor, and system fonts.
|
||||
- [ ] A single static Nord wallpaper is set by Stylix; no dynamic, animated, or cycling wallpaper.
|
||||
- [ ] Stylix targets for nvim, tmux, and fish are off, leaving their existing themes untouched.
|
||||
- [ ] neogaia builds green under `nix flake check`, and an eval probe confirms the resolved scheme is Nord.
|
||||
- [x] Stylix is a flake input, wired into the host build.
|
||||
- [x] A desktop theming module resolves a single Nord base16 scheme and applies it to GTK, Qt, cursor, and system fonts.
|
||||
- [x] A single static Nord wallpaper is set by Stylix; no dynamic, animated, or cycling wallpaper.
|
||||
- [x] Stylix targets for nvim, tmux, and fish are off, leaving their existing themes untouched.
|
||||
- [x] neogaia builds green under `nix flake check`, and an eval probe confirms the resolved scheme is Nord.
|
||||
|
||||
## Implementation Notes
|
||||
|
||||
- **Wallpaper is a generated Nord gradient, not a shipped image.**
|
||||
Stylix requires an `image`, and the spec asks only for "a single static Nord wallpaper".
|
||||
Rather than commit a binary blob or fetch one over the network at build time, the module draws a vertical gradient across the Nord Polar Night shades (`#2E3440` → `#3B4252`) with ImageMagick.
|
||||
It is static, genuinely Nord, and fully reproducible with no external dependency beyond a cached build tool.
|
||||
Swapping in a picture later is a one-line change to `image`.
|
||||
|
||||
- **The nvim target is `nixvim`, not `neovim`.**
|
||||
nvim here is configured through nixvim, so the Stylix target that would theme it is `nixvim`.
|
||||
Disabling `neovim` would have been a no-op and left nvim themed.
|
||||
|
||||
- **fish is disabled at two levels.**
|
||||
fish is enabled both at system level (`programs.fish`, for `/etc/shells` and vendor completions) and in home-manager, so its theming has a target in each scope.
|
||||
Both are turned off, so the hand-written fish theme stands.
|
||||
|
||||
- **Cursor generation switched on explicitly.**
|
||||
home-manager now wants `home.pointerCursor.enable` set explicitly rather than inferring it from the presence of cursor settings, so the module sets it to silence the deprecation and keep the build warning-clean (bar the pre-existing benign nixvim `nixpkgs.follows` notice).
|
||||
|
||||
- **System font pinned to JetBrains Mono.**
|
||||
The acceptance criterion asks for "system fonts" without naming one, so the monospace is pinned to JetBrains Mono and the serif/sans/emoji families are left at Stylix's Nord-coherent defaults.
|
||||
|
||||
- **Stylix module imported unconditionally.**
|
||||
`lib.nix` adds `inputs.stylix.nixosModules.stylix` to every host's module set, matching how the other input modules are wired.
|
||||
It stays inert until `stylix.enable` is set, which only the theming module does, only when the desktop is on.
|
||||
|
||||
280
flake.lock
generated
280
flake.lock
generated
@@ -1,5 +1,73 @@
|
||||
{
|
||||
"nodes": {
|
||||
"base16": {
|
||||
"inputs": {
|
||||
"fromYaml": "fromYaml"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1755819240,
|
||||
"narHash": "sha256-qcMhnL7aGAuFuutH4rq9fvAhCpJWVHLcHVZLtPctPlo=",
|
||||
"owner": "SenchoPens",
|
||||
"repo": "base16.nix",
|
||||
"rev": "75ed5e5e3fce37df22e49125181fa37899c3ccd6",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "SenchoPens",
|
||||
"repo": "base16.nix",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"base16-fish": {
|
||||
"flake": false,
|
||||
"locked": {
|
||||
"lastModified": 1765809053,
|
||||
"narHash": "sha256-XCUQLoLfBJ8saWms2HCIj4NEN+xNsWBlU1NrEPcQG4s=",
|
||||
"owner": "tomyun",
|
||||
"repo": "base16-fish",
|
||||
"rev": "86cbea4dca62e08fb7fd83a70e96472f92574782",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "tomyun",
|
||||
"repo": "base16-fish",
|
||||
"rev": "86cbea4dca62e08fb7fd83a70e96472f92574782",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"base16-helix": {
|
||||
"flake": false,
|
||||
"locked": {
|
||||
"lastModified": 1776754714,
|
||||
"narHash": "sha256-E3OAK27smtATTmX45uoTSRsVD+Y+ZiVVfgM/tjpbtYg=",
|
||||
"owner": "tinted-theming",
|
||||
"repo": "base16-helix",
|
||||
"rev": "4d508123037e7851ad36ebf7d9c48b0e9e1eb581",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "tinted-theming",
|
||||
"repo": "base16-helix",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"base16-vim": {
|
||||
"flake": false,
|
||||
"locked": {
|
||||
"lastModified": 1732806396,
|
||||
"narHash": "sha256-e0bpPySdJf0F68Ndanwm+KWHgQiZ0s7liLhvJSWDNsA=",
|
||||
"owner": "tinted-theming",
|
||||
"repo": "base16-vim",
|
||||
"rev": "577fe8125d74ff456cf942c733a85d769afe58b7",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "tinted-theming",
|
||||
"repo": "base16-vim",
|
||||
"rev": "577fe8125d74ff456cf942c733a85d769afe58b7",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"chaotic": {
|
||||
"inputs": {
|
||||
"flake-schemas": "flake-schemas",
|
||||
@@ -41,6 +109,22 @@
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"firefox-gnome-theme": {
|
||||
"flake": false,
|
||||
"locked": {
|
||||
"lastModified": 1782007937,
|
||||
"narHash": "sha256-PbnJr+eB+9Czol3ReI83dUgEhcn0sDK6TSy6ODTQm88=",
|
||||
"owner": "rafaelmardojai",
|
||||
"repo": "firefox-gnome-theme",
|
||||
"rev": "981bd332015397fb1ca033fa982bd61635160c78",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "rafaelmardojai",
|
||||
"repo": "firefox-gnome-theme",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"flake-parts": {
|
||||
"inputs": {
|
||||
"nixpkgs-lib": [
|
||||
@@ -62,6 +146,27 @@
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"flake-parts_2": {
|
||||
"inputs": {
|
||||
"nixpkgs-lib": [
|
||||
"stylix",
|
||||
"nixpkgs"
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1782949081,
|
||||
"narHash": "sha256-vp6Y/Grm98ESt6ceOkWiHWyZRDV3J1RID4w+6NWK9yA=",
|
||||
"owner": "hercules-ci",
|
||||
"repo": "flake-parts",
|
||||
"rev": "17c9d6cdfc60c64f4ee8d306f9bc0b4ccb51481e",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "hercules-ci",
|
||||
"repo": "flake-parts",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"flake-schemas": {
|
||||
"locked": {
|
||||
"lastModified": 1780327564,
|
||||
@@ -76,6 +181,22 @@
|
||||
"url": "https://flakehub.com/f/DeterminateSystems/flake-schemas/%3D0.5.0.tar.gz"
|
||||
}
|
||||
},
|
||||
"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"
|
||||
}
|
||||
},
|
||||
"gitea-axi": {
|
||||
"inputs": {
|
||||
"home-manager": "home-manager_2",
|
||||
@@ -97,6 +218,25 @@
|
||||
"url": "https://git.alexion.dev/alexion/gitea-axi"
|
||||
}
|
||||
},
|
||||
"gnome-shell": {
|
||||
"flake": false,
|
||||
"locked": {
|
||||
"host": "gitlab.gnome.org",
|
||||
"lastModified": 1776175984,
|
||||
"narHash": "sha256-RJFlFW8GiMei6oqUGrMkGEvVqOH8U7Q8abc1yK4VKD8=",
|
||||
"owner": "GNOME",
|
||||
"repo": "gnome-shell",
|
||||
"rev": "e0fdc4c13250e9a9b8ea9594c83925274f4a5dca",
|
||||
"type": "gitlab"
|
||||
},
|
||||
"original": {
|
||||
"host": "gitlab.gnome.org",
|
||||
"owner": "GNOME",
|
||||
"ref": "50.1",
|
||||
"repo": "gnome-shell",
|
||||
"type": "gitlab"
|
||||
}
|
||||
},
|
||||
"home-manager": {
|
||||
"inputs": {
|
||||
"nixpkgs": [
|
||||
@@ -265,6 +405,31 @@
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nur": {
|
||||
"inputs": {
|
||||
"flake-parts": [
|
||||
"stylix",
|
||||
"flake-parts"
|
||||
],
|
||||
"nixpkgs": [
|
||||
"stylix",
|
||||
"nixpkgs"
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1783439237,
|
||||
"narHash": "sha256-WUr8JF2v3n4Y30E5dxv4sAgNJXpVDBoCQNoQ/V4+n4o=",
|
||||
"owner": "nix-community",
|
||||
"repo": "NUR",
|
||||
"rev": "b70bb66c7bcd162642f3a609bc16843c7059f503",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "nix-community",
|
||||
"repo": "NUR",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"root": {
|
||||
"inputs": {
|
||||
"chaotic": "chaotic",
|
||||
@@ -276,7 +441,8 @@
|
||||
"nixpkgs-stable": "nixpkgs-stable",
|
||||
"nixpkgs-unstable": "nixpkgs-unstable",
|
||||
"nixvim": "nixvim",
|
||||
"sops-nix": "sops-nix"
|
||||
"sops-nix": "sops-nix",
|
||||
"stylix": "stylix"
|
||||
}
|
||||
},
|
||||
"sops-nix": {
|
||||
@@ -299,6 +465,39 @@
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"stylix": {
|
||||
"inputs": {
|
||||
"base16": "base16",
|
||||
"base16-fish": "base16-fish",
|
||||
"base16-helix": "base16-helix",
|
||||
"base16-vim": "base16-vim",
|
||||
"firefox-gnome-theme": "firefox-gnome-theme",
|
||||
"flake-parts": "flake-parts_2",
|
||||
"gnome-shell": "gnome-shell",
|
||||
"nixpkgs": [
|
||||
"nixpkgs"
|
||||
],
|
||||
"nur": "nur",
|
||||
"systems": "systems_2",
|
||||
"tinted-kitty": "tinted-kitty",
|
||||
"tinted-schemes": "tinted-schemes",
|
||||
"tinted-tmux": "tinted-tmux",
|
||||
"tinted-zed": "tinted-zed"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1784676123,
|
||||
"narHash": "sha256-ndyanKzw90yX2nUVFmTuYqXidUNymtMfgmIHyNdhht0=",
|
||||
"owner": "danth",
|
||||
"repo": "stylix",
|
||||
"rev": "66714e5ce44269ecc58c20d9196da8dbe1b27a31",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "danth",
|
||||
"repo": "stylix",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"systems": {
|
||||
"locked": {
|
||||
"lastModified": 1774449309,
|
||||
@@ -314,6 +513,85 @@
|
||||
"repo": "default",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"systems_2": {
|
||||
"locked": {
|
||||
"lastModified": 1681028828,
|
||||
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
|
||||
"owner": "nix-systems",
|
||||
"repo": "default",
|
||||
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "nix-systems",
|
||||
"repo": "default",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"tinted-kitty": {
|
||||
"flake": false,
|
||||
"locked": {
|
||||
"lastModified": 1735730497,
|
||||
"narHash": "sha256-4KtB+FiUzIeK/4aHCKce3V9HwRvYaxX+F1edUrfgzb8=",
|
||||
"owner": "tinted-theming",
|
||||
"repo": "tinted-kitty",
|
||||
"rev": "de6f888497f2c6b2279361bfc790f164bfd0f3fa",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "tinted-theming",
|
||||
"repo": "tinted-kitty",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"tinted-schemes": {
|
||||
"flake": false,
|
||||
"locked": {
|
||||
"lastModified": 1781968807,
|
||||
"narHash": "sha256-yYO3Vw2M0y3TAUqt+9+Mj0zwP3XDTF5/PXcPhhFQ1ZM=",
|
||||
"owner": "tinted-theming",
|
||||
"repo": "schemes",
|
||||
"rev": "2ccef2f4b22e3cab5a9292811f7133a07eeba4a7",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "tinted-theming",
|
||||
"repo": "schemes",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"tinted-tmux": {
|
||||
"flake": false,
|
||||
"locked": {
|
||||
"lastModified": 1782012462,
|
||||
"narHash": "sha256-2iDiD8DQLwS1lGuD9TS8WlvNyDoTs6krWntJbtB2zGo=",
|
||||
"owner": "tinted-theming",
|
||||
"repo": "tinted-tmux",
|
||||
"rev": "8c4e750f738a742bd73377ee41d3dadedebedef4",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "tinted-theming",
|
||||
"repo": "tinted-tmux",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"tinted-zed": {
|
||||
"flake": false,
|
||||
"locked": {
|
||||
"lastModified": 1782009766,
|
||||
"narHash": "sha256-VUhBjpGvWqHI7rWeyMYb/u87YJSXHKfVV6S+IelWeO8=",
|
||||
"owner": "tinted-theming",
|
||||
"repo": "base16-zed",
|
||||
"rev": "5e8350bcd354e3241ab681a265fa6ef060c40be1",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "tinted-theming",
|
||||
"repo": "base16-zed",
|
||||
"type": "github"
|
||||
}
|
||||
}
|
||||
},
|
||||
"root": "root",
|
||||
|
||||
@@ -40,6 +40,13 @@
|
||||
inputs.nixpkgs.follows = "nixpkgs";
|
||||
};
|
||||
|
||||
# Themes the graphical layer from one base16 scheme.
|
||||
# Follows our nixpkgs so it themes the same package set the host builds.
|
||||
stylix = {
|
||||
url = "github:danth/stylix";
|
||||
inputs.nixpkgs.follows = "nixpkgs";
|
||||
};
|
||||
|
||||
# Agent-ergonomic CLI for Gitea, with its home-manager module wiring in the
|
||||
# Claude Code context where that harness is present.
|
||||
gitea-axi = {
|
||||
|
||||
1
lib.nix
1
lib.nix
@@ -51,6 +51,7 @@ let
|
||||
inputs.chaotic.nixosModules.default
|
||||
inputs.disko.nixosModules.disko
|
||||
inputs.sops-nix.nixosModules.sops
|
||||
inputs.stylix.nixosModules.stylix
|
||||
(self + "/system.nix")
|
||||
(self + "/hosts/${hostName}")
|
||||
{ networking.hostName = hostName; }
|
||||
|
||||
@@ -12,5 +12,6 @@ in
|
||||
modules.desktop.hyprland.enable = lib.mkDefault true;
|
||||
modules.desktop.login.enable = lib.mkDefault true;
|
||||
modules.desktop.terminal.enable = lib.mkDefault true;
|
||||
modules.desktop.theming.enable = lib.mkDefault true;
|
||||
};
|
||||
}
|
||||
|
||||
65
modules/desktop/theming.nix
Normal file
65
modules/desktop/theming.nix
Normal file
@@ -0,0 +1,65 @@
|
||||
{
|
||||
config,
|
||||
lib,
|
||||
pkgs,
|
||||
...
|
||||
}:
|
||||
# Nord theming for the graphical layer, driven from one base16 scheme by Stylix.
|
||||
let
|
||||
cfg = config.modules.desktop.theming;
|
||||
user = config.user.name;
|
||||
|
||||
# A single static Nord wallpaper, drawn as a vertical gradient across the
|
||||
# Polar Night shades so it needs no committed binary and no network fetch.
|
||||
wallpaper = pkgs.runCommand "nord-wallpaper.png" { } ''
|
||||
${pkgs.imagemagick}/bin/magick \
|
||||
-size 2560x1440 gradient:'#2E3440'-'#3B4252' \
|
||||
"$out"
|
||||
'';
|
||||
in
|
||||
{
|
||||
options.modules.desktop.theming.enable =
|
||||
lib.mkEnableOption "Nord theming of the graphical layer via Stylix";
|
||||
|
||||
config = lib.mkIf cfg.enable {
|
||||
stylix = {
|
||||
enable = true;
|
||||
|
||||
# Nord is a dark scheme.
|
||||
# The polarity steers Stylix's contrast choices.
|
||||
polarity = "dark";
|
||||
base16Scheme = "${pkgs.base16-schemes}/share/themes/nord.yaml";
|
||||
|
||||
image = wallpaper;
|
||||
|
||||
cursor = {
|
||||
package = pkgs.bibata-cursors;
|
||||
name = "Bibata-Modern-Ice";
|
||||
size = 24;
|
||||
};
|
||||
|
||||
fonts.monospace = {
|
||||
package = pkgs.jetbrains-mono;
|
||||
name = "JetBrains Mono";
|
||||
};
|
||||
|
||||
# fish is also installed at system level, so its theming has a target
|
||||
# here of its own.
|
||||
targets.fish.enable = false;
|
||||
};
|
||||
|
||||
home-manager.users.${user} = {
|
||||
# Stylix drives the cursor through home-manager's pointer-cursor config,
|
||||
# whose generation must be switched on explicitly.
|
||||
home.pointerCursor.enable = true;
|
||||
|
||||
# nvim, tmux, and fish are configured through home-manager and keep their
|
||||
# own hand-written themes, so their Stylix targets stay off.
|
||||
stylix.targets = {
|
||||
fish.enable = false;
|
||||
|
alexion marked this conversation as resolved
|
||||
tmux.enable = false;
|
||||
nixvim.enable = false;
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user
Done in
6d1afa4. Onlynixvimstays off now; tmux and fish are Stylix-managed.fish had no colour theme of its own, so that was a clean flip. tmux did — a hand-written Nord status bar in
extra.conf— which would have fought Stylix, so I removed those colour lines and let Stylix theme the status and pane styles. I kept your minimal layout (session name + window list, empty right side) and it's reapplied after Stylix's theme, so the layout still wins while the colours come from the one scheme.Verified on the rendered
tmux.conf: Stylix sourcesbase16-nord.confbefore your layout block, its unconditional colour lines apply, and its optional verbose statusbar stays gated off — so no clobbering.nix flake checkis green.— Claude