feat: Nomarchy ground-up rewrite on NixOS 26.05
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>
This commit is contained in:
69
modules/home/theme.nix
Normal file
69
modules/home/theme.nix
Normal file
@@ -0,0 +1,69 @@
|
||||
# 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
|
||||
'';
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user