feat(nightlight): menu-driven, in-flake on/off (no ~/.local/state)

Night light is off by default and configured entirely through the menu,
writing into the downstream flake instead of ~/.local/state — so the
choice is git-tracked and reproducible across a clone+rebuild.

Two flags under a new settings.* section of the state file (exposed as
the nomarchy.settings option):
- settings.nightlight.installed — sticky, gates the hyprsunset unit;
  nomarchy.nightlight.enable mkDefault-reads it. First enable from the
  menu rebuilds to create the unit (the one accepted rebuild).
- settings.nightlight.on — runtime on/off, toggled instantly
  (theme-sync set --no-switch + systemctl), no rebuild. An ExecCondition
  reads the live flag at session start so an off survives reboot;
  splitting it from the sticky flag means a later unrelated rebuild
  never undoes an instant-off (no decay).

Drops the ~/.local/state/nomarchy/nightlight-off marker and the
ConditionPathExists hack. theme-sync set now skips the wallpaper
re-apply for non-wallpaper keys, and its rebuild notifications are
generic ("changes" not "theme").

First cut of the broader principle — any user-settable config gets a
menu writer that lands it in the flake; no state outside the checkout.
Docs (README §4, ROADMAP, template) updated to reflect it.

Eval- and round-trip-verified; on-hardware check pending.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Bernardo Magri
2026-06-21 20:24:58 +01:00
parent c8d0b09044
commit 685126ab47
10 changed files with 144 additions and 75 deletions

View File

@@ -54,6 +54,12 @@ let
# tone for kanagawa/summer-*). Each preset declares its own so a theme
# switch always replaces it (deep_merge would otherwise leave it stuck).
border = { active = "accent"; inactive = "overlay"; };
# Non-appearance feature settings the menu writes into this same in-flake
# state. nomarchy.nightlight: `installed` (sticky — gates the unit, so the
# first enable rebuilds) and `on` (instant runtime on/off). Defaulted so a
# sparse/older state file still evaluates; nomarchy.settings exposes them.
settings.nightlight = { installed = false; on = true; };
};
parsed = lib.recursiveUpdate defaults themeState;
@@ -78,6 +84,11 @@ in
config = {
nomarchy.theme = parsed // { inherit iconTheme border; };
# Feature toggles the menu writes (settings.nightlight.enable, …), exposed
# alongside the appearance state. Feature modules mkDefault-read from here
# so a menu toggle lands in the flake instead of in ~/.local/state.
nomarchy.settings = parsed.settings;
nomarchy.lib = {
# "#7aa2f7" -> "rgb(7aa2f7)" (Hyprland color syntax)
rgb = c: "rgb(${lib.removePrefix "#" c})";