Full replacement of the previous iteration, rebuilt around three ideas:
- Pure evaluation: theme-state.json lives inside the flake and is read
via the nomarchy.stateFile option — no --impure, ever.
- All-Home-Manager theming: `nomarchy-theme-sync apply` writes the JSON
and runs `home-manager switch`; every theme change is one atomic,
rollbackable generation. Wallpaper (swww) is the sole runtime piece.
- Flat, downstream-first layout: modules/{nixos,home} with one
options.nix each, exported as nixosModules/homeModules + overlay +
flake template; system (nixos-rebuild) and desktop (home-manager
switch) rebuild paths are fully split.
Ships 21 themes imported from the previous iteration (palettes,
wallpapers, btop themes, six whole-swap Waybar identities), Stylix for
the GTK/Qt/cursor long tail, a live ISO target with offline theme
switching, and docs/TESTING.md with the QEMU verification workflow.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
70 lines
2.3 KiB
Nix
70 lines
2.3 KiB
Nix
# Nomarchy theming engine.
|
|
#
|
|
# nomarchy.stateFile (theme-state.json, inside the consuming flake) is
|
|
# ingested at evaluation time — pure, because flake files are store
|
|
# paths — and exposed to every other module as `config.nomarchy.theme`.
|
|
#
|
|
# Theme changes are fully Home Manager managed: `nomarchy-theme-sync
|
|
# apply <theme>` writes the JSON and runs `home-manager switch`, baking
|
|
# everything (Hyprland, Waybar, Ghostty, btop, Stylix) into one
|
|
# read-only generation. No runtime patching, no partial states; theme
|
|
# history is generation history.
|
|
#
|
|
# The one runtime exception is the wallpaper (swww is imperative by
|
|
# nature): applied at session start, after every switch (hook below),
|
|
# and cycled instantly with `nomarchy-theme-sync bg next`.
|
|
{ config, lib, pkgs, ... }:
|
|
|
|
let
|
|
cfg = config.nomarchy;
|
|
|
|
themeState = builtins.fromJSON (builtins.readFile cfg.stateFile);
|
|
|
|
# Defaults guarantee evaluation succeeds on a sparse or older state
|
|
# file (e.g. one written before a schema field was added). The shipped
|
|
# Tokyo Night preset provides the color/ansi fallbacks; the path is
|
|
# relative to this module, so it resolves inside Nomarchy's own flake
|
|
# source even when consumed downstream.
|
|
preset = builtins.fromJSON (builtins.readFile ../../themes/tokyo-night.json);
|
|
|
|
defaults = preset // {
|
|
fonts = {
|
|
mono = "JetBrainsMono Nerd Font";
|
|
ui = "Inter";
|
|
size = 11;
|
|
};
|
|
ui = {
|
|
gapsIn = 5;
|
|
gapsOut = 12;
|
|
borderSize = 2;
|
|
rounding = 10;
|
|
activeOpacity = 1.0;
|
|
inactiveOpacity = 0.95;
|
|
terminalOpacity = 0.96;
|
|
blur = true;
|
|
shadow = true;
|
|
};
|
|
};
|
|
in
|
|
{
|
|
config = {
|
|
nomarchy.theme = lib.recursiveUpdate defaults themeState;
|
|
|
|
nomarchy.lib = {
|
|
# "#7aa2f7" -> "rgb(7aa2f7)" (Hyprland color syntax)
|
|
rgb = c: "rgb(${lib.removePrefix "#" c})";
|
|
# "#16161e" -> "rgba(16161eaa)" (Hyprland color + hex alpha)
|
|
rgba = c: alpha: "rgba(${lib.removePrefix "#" c}${alpha})";
|
|
};
|
|
|
|
home.packages = [ cfg.package ];
|
|
|
|
# After a switch the new theme's wallpaper should show without
|
|
# logging out. Best-effort: outside a graphical session swww isn't
|
|
# running and this is a no-op.
|
|
home.activation.nomarchyWallpaper = lib.hm.dag.entryAfter [ "writeBoundary" ] ''
|
|
run ${lib.getExe cfg.package} --quiet wallpaper || true
|
|
'';
|
|
};
|
|
}
|