refactor: major architectural restructure for theme-centric organization

Theme System:
- Move all theme app configs to apps/ subdirectory (20 themes)
- Add theme-loader.nix for dynamic theme config deployment
- Simplify stylix.nix to focus on base theming only

Override System:
- Add overrides.nix for file-based config overrides
- Add behavior-configs.nix for non-visual configuration
- Split hypr/nomarchy.conf into behavior vs visual sections

Module Improvements:
- Add lib.mkDefault to all customizable settings
- Add modules/lib/ with shared utilities and state schema
- Update all home and system modules for downstream overridability

Installer:
- New minimal TTY installer (installer/install.sh)
- Golden path: BTRFS + LUKS2 (disko-golden.nix)
- New installer-iso.nix for TTY-only installation
- Keep graphical installer as installerIsoGraphical option

Cleanup:
- Remove obsolete install.sh, disko-ext4.nix, install-nomarchy.sh
- Update live-iso.nix references
- Add .claude/ to .gitignore for local IDE settings

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
Bernardo Magri
2026-04-11 19:38:27 +01:00
parent 769fd88f25
commit b27fc5aee8
141 changed files with 2014 additions and 943 deletions

View File

@@ -14,13 +14,13 @@ if [ ! -f "$STATE_FILE" ]; then
echo "[]" > "$STATE_FILE"
fi
if jq -e ". | index(\"$PKG_NAME\")" "$STATE_FILE" >/dev/null; then
if jq -e --arg pkg "$PKG_NAME" '. | index($pkg)' "$STATE_FILE" >/dev/null; then
echo "Package $PKG_NAME is already in your user-packages.json"
exit 0
fi
# Append package to the JSON array
jq ". + [\"$PKG_NAME\"]" "$STATE_FILE" > "${STATE_FILE}.tmp" && mv "${STATE_FILE}.tmp" "$STATE_FILE"
# Append package to the JSON array safely
jq --arg pkg "$PKG_NAME" '. + [$pkg]' "$STATE_FILE" > "${STATE_FILE}.tmp" && mv "${STATE_FILE}.tmp" "$STATE_FILE"
echo "Package $PKG_NAME added declaratively to $STATE_FILE."
echo "Applying changes with env-update..."

View File

@@ -14,13 +14,13 @@ if [ ! -f "$STATE_FILE" ]; then
exit 0
fi
if ! jq -e ". | index(\"$PKG_NAME\")" "$STATE_FILE" >/dev/null; then
if ! jq -e --arg pkg "$PKG_NAME" '. | index($pkg)' "$STATE_FILE" >/dev/null; then
echo "Package $PKG_NAME is not in your user-packages.json"
exit 0
fi
# Remove package from the JSON array
jq ". - [\"$PKG_NAME\"]" "$STATE_FILE" > "${STATE_FILE}.tmp" && mv "${STATE_FILE}.tmp" "$STATE_FILE"
# Remove package from the JSON array safely
jq --arg pkg "$PKG_NAME" '. - [$pkg]' "$STATE_FILE" > "${STATE_FILE}.tmp" && mv "${STATE_FILE}.tmp" "$STATE_FILE"
echo "Package $PKG_NAME removed declaratively from $STATE_FILE."
echo "Applying changes with env-update..."

View File

@@ -2,22 +2,32 @@
# Nomarchy Pre-flight State Migration
# Migrates legacy state files into the unified state.json before Nix evaluation
STATE_DIR="$HOME/.config/home-manager"
STATE_DIR="$HOME/.config/nomarchy"
OLD_STATE_DIR="$HOME/.config/home-manager"
OLD_TOGGLES_DIR="$HOME/.local/state/nomarchy/toggles"
IDLE_STATE_FILE="$STATE_DIR/idle-state.json"
NIGHTLIGHT_STATE_FILE="$STATE_DIR/hyprsunset-state.json"
HYPRLAND_STATE_FILE="$STATE_DIR/hyprland-state.json"
THEME_STATE_FILE="$STATE_DIR/theme-state.nix"
WALLPAPER_STATE_FILE="$STATE_DIR/wallpaper-state.nix"
FONT_STATE_FILE="$STATE_DIR/font-state.nix"
IDLE_STATE_FILE="$OLD_STATE_DIR/idle-state.json"
NIGHTLIGHT_STATE_FILE="$OLD_STATE_DIR/hyprsunset-state.json"
HYPRLAND_STATE_FILE="$OLD_STATE_DIR/hyprland-state.json"
THEME_STATE_FILE="$OLD_STATE_DIR/theme-state.nix"
WALLPAPER_STATE_FILE="$OLD_STATE_DIR/wallpaper-state.nix"
FONT_STATE_FILE="$OLD_STATE_DIR/font-state.nix"
OLD_STATE_FILE="$OLD_STATE_DIR/state.json"
NEW_STATE_FILE="$STATE_DIR/state.json"
# We expect jq to be in PATH (it's a dependency of nomarchy-scripts)
JQ="jq"
mkdir -p "$(dirname "$NEW_STATE_FILE")"
mkdir -p "$STATE_DIR"
[[ ! -f $NEW_STATE_FILE ]] && echo "{}" > "$NEW_STATE_FILE"
# 0. Migrate from old home-manager state.json location
if [[ -f "$OLD_STATE_FILE" ]] && [[ "$OLD_STATE_FILE" != "$NEW_STATE_FILE" ]]; then
# Merge old state into new state
TMP_FILE=$(mktemp)
$JQ -s '.[0] * .[1]' "$OLD_STATE_FILE" "$NEW_STATE_FILE" > "$TMP_FILE" && mv "$TMP_FILE" "$NEW_STATE_FILE"
rm "$OLD_STATE_FILE" 2>/dev/null || true
fi
# 1. Migrate .local/state/nomarchy/toggles
if [[ -d $OLD_TOGGLES_DIR ]]; then
for file in "$OLD_TOGGLES_DIR"/*; do
@@ -43,7 +53,7 @@ fi
if [[ -f $IDLE_STATE_FILE ]]; then
ENABLED=$($JQ '.enabled' "$IDLE_STATE_FILE")
if [[ "$ENABLED" == "true" || "$ENABLED" == "false" ]]; then
$JQ ".idle = $ENABLED" "$NEW_STATE_FILE" > "$NEW_STATE_FILE.tmp" && mv "$NEW_STATE_FILE.tmp" "$NEW_STATE_FILE"
$JQ --argjson val "$ENABLED" '.idle = $val' "$NEW_STATE_FILE" > "$NEW_STATE_FILE.tmp" && mv "$NEW_STATE_FILE.tmp" "$NEW_STATE_FILE"
fi
rm "$IDLE_STATE_FILE"
fi
@@ -51,7 +61,7 @@ fi
if [[ -f $NIGHTLIGHT_STATE_FILE ]]; then
ENABLED=$($JQ '.enabled' "$NIGHTLIGHT_STATE_FILE")
TEMP=$($JQ '.temperature' "$NIGHTLIGHT_STATE_FILE")
$JQ ".nightlight = $ENABLED | .nightlightTemperature = $TEMP" "$NEW_STATE_FILE" > "$NEW_STATE_FILE.tmp" && mv "$NEW_STATE_FILE.tmp" "$NEW_STATE_FILE"
$JQ --argjson enabled "$ENABLED" --argjson temp "$TEMP" '.nightlight = $enabled | .nightlightTemperature = $temp' "$NEW_STATE_FILE" > "$NEW_STATE_FILE.tmp" && mv "$NEW_STATE_FILE.tmp" "$NEW_STATE_FILE"
rm "$NIGHTLIGHT_STATE_FILE"
fi
@@ -59,25 +69,25 @@ if [[ -f $HYPRLAND_STATE_FILE ]]; then
GAPS_OUT=$($JQ '.gaps_out' "$HYPRLAND_STATE_FILE")
GAPS_IN=$($JQ '.gaps_in' "$HYPRLAND_STATE_FILE")
BORDER_SIZE=$($JQ '.border_size' "$HYPRLAND_STATE_FILE")
$JQ ".hyprland = {\"gaps_out\": $GAPS_OUT, \"gaps_in\": $GAPS_IN, \"border_size\": $BORDER_SIZE}" "$NEW_STATE_FILE" > "$NEW_STATE_FILE.tmp" && mv "$NEW_STATE_FILE.tmp" "$NEW_STATE_FILE"
$JQ --argjson go "$GAPS_OUT" --argjson gi "$GAPS_IN" --argjson bs "$BORDER_SIZE" '.hyprland = {"gaps_out": $go, "gaps_in": $gi, "border_size": $bs}' "$NEW_STATE_FILE" > "$NEW_STATE_FILE.tmp" && mv "$NEW_STATE_FILE.tmp" "$NEW_STATE_FILE"
rm "$HYPRLAND_STATE_FILE"
fi
# 3. Migrate plaintext string state files
if [[ -f $THEME_STATE_FILE ]]; then
THEME=$(cat "$THEME_STATE_FILE" | tr -d '\n')
$JQ ".theme = \"$THEME\"" "$NEW_STATE_FILE" > "$NEW_STATE_FILE.tmp" && mv "$NEW_STATE_FILE.tmp" "$NEW_STATE_FILE"
$JQ --arg theme "$THEME" '.theme = $theme' "$NEW_STATE_FILE" > "$NEW_STATE_FILE.tmp" && mv "$NEW_STATE_FILE.tmp" "$NEW_STATE_FILE"
rm "$THEME_STATE_FILE"
fi
if [[ -f $WALLPAPER_STATE_FILE ]]; then
WALLPAPER=$(cat "$WALLPAPER_STATE_FILE" | tr -d '\n')
$JQ ".wallpaper = \"$WALLPAPER\"" "$NEW_STATE_FILE" > "$NEW_STATE_FILE.tmp" && mv "$NEW_STATE_FILE.tmp" "$NEW_STATE_FILE"
$JQ --arg wp "$WALLPAPER" '.wallpaper = $wp' "$NEW_STATE_FILE" > "$NEW_STATE_FILE.tmp" && mv "$NEW_STATE_FILE.tmp" "$NEW_STATE_FILE"
rm "$WALLPAPER_STATE_FILE"
fi
if [[ -f $FONT_STATE_FILE ]]; then
FONT=$(cat "$FONT_STATE_FILE" | tr -d '\n')
$JQ ".font = \"$FONT\"" "$NEW_STATE_FILE" > "$NEW_STATE_FILE.tmp" && mv "$NEW_STATE_FILE.tmp" "$NEW_STATE_FILE"
$JQ --arg font "$FONT" '.font = $font' "$NEW_STATE_FILE" > "$NEW_STATE_FILE.tmp" && mv "$NEW_STATE_FILE.tmp" "$NEW_STATE_FILE"
rm "$FONT_STATE_FILE"
fi

View File

@@ -13,7 +13,7 @@ fi
case "$dns" in
Cloudflare|Google|DHCP)
sudo jq ".dns = \"$dns\"" "$STATE_FILE" > /tmp/state.json && sudo mv /tmp/state.json "$STATE_FILE"
sudo jq --arg dns "$dns" '.dns = $dns' "$STATE_FILE" > /tmp/state.json && sudo mv /tmp/state.json "$STATE_FILE"
;;
Custom)
@@ -24,10 +24,10 @@ Custom)
echo "Error: No DNS servers provided."
exit 1
fi
# Convert to JSON array
# Convert to JSON array safely
dns_array=$(echo "$dns_servers" | jq -R 'split(" ")')
sudo jq ".dns = \"Custom\" | .customDns = $dns_array" "$STATE_FILE" > /tmp/state.json && sudo mv /tmp/state.json "$STATE_FILE"
sudo jq --arg dns "Custom" --argjson servers "$dns_array" '.dns = $dns | .customDns = $servers' "$STATE_FILE" > /tmp/state.json && sudo mv /tmp/state.json "$STATE_FILE"
;;
esac

View File

@@ -5,13 +5,13 @@
STATE_FILE="/etc/nixos/state.json"
if [[ "--remove" == $1 ]]; then
sudo jq ".features.fido2 = false" "$STATE_FILE" > /tmp/state.json && sudo mv /tmp/state.json "$STATE_FILE"
sudo jq '.features.fido2 = false' "$STATE_FILE" > /tmp/state.json && sudo mv /tmp/state.json "$STATE_FILE"
echo "FIDO2 support disabled. Applying changes..."
sudo sys-update
exit 0
fi
sudo jq ".features.fido2 = true" "$STATE_FILE" > /tmp/state.json && sudo mv /tmp/state.json "$STATE_FILE"
sudo jq '.features.fido2 = true' "$STATE_FILE" > /tmp/state.json && sudo mv /tmp/state.json "$STATE_FILE"
echo "FIDO2 support enabled. Applying changes..."
sudo sys-update

View File

@@ -5,13 +5,13 @@
STATE_FILE="/etc/nixos/state.json"
if [[ "--remove" == $1 ]]; then
sudo jq ".features.fingerprint = false" "$STATE_FILE" > /tmp/state.json && sudo mv /tmp/state.json "$STATE_FILE"
sudo jq '.features.fingerprint = false' "$STATE_FILE" > /tmp/state.json && sudo mv /tmp/state.json "$STATE_FILE"
echo "Fingerprint support disabled. Applying changes..."
sudo sys-update
exit 0
fi
sudo jq ".features.fingerprint = true" "$STATE_FILE" > /tmp/state.json && sudo mv /tmp/state.json "$STATE_FILE"
sudo jq '.features.fingerprint = true' "$STATE_FILE" > /tmp/state.json && sudo mv /tmp/state.json "$STATE_FILE"
echo "Fingerprint support enabled. Applying changes..."
sudo sys-update

View File

@@ -3,24 +3,25 @@
# Toggles the idle daemon (hypridle) between enabled and disabled.
# Hybrid: updates state.json and provides instant feedback.
STATE_FILE="$HOME/.config/home-manager/state.json"
mkdir -p "$(dirname "$STATE_FILE")"
STATE_DIR="$HOME/.config/nomarchy"
STATE_FILE="$STATE_DIR/state.json"
mkdir -p "$STATE_DIR"
# Initialize if doesn't exist
[[ ! -f $STATE_FILE ]] && echo "{}" > "$STATE_FILE"
if [[ $NNOMARCHY_TOGGLE_IDLE == "false" ]]; then
if [[ $NOMARCHY_TOGGLE_IDLE == "false" ]]; then
NEW_VALUE="true"
setsid hypridle >/dev/null 2>&1 &
notify-send -u low "󱫖 Now locking computer when idle"
notify-send -u low " Now locking computer when idle"
else
NEW_VALUE="false"
pkill -x hypridle
notify-send -u low "󱫖 Stop locking computer when idle"
notify-send -u low " Stop locking computer when idle"
fi
TMP_JSON=$(mktemp)
jq ".idle = $NEW_VALUE" "$STATE_FILE" > "$TMP_JSON" && mv "$TMP_JSON" "$STATE_FILE"
jq --argjson val "$NEW_VALUE" '.idle = $val' "$STATE_FILE" > "$TMP_JSON" && mv "$TMP_JSON" "$STATE_FILE"
echo "Idle state set to $NEW_VALUE. Environment will be fully updated on next rebuild."

View File

@@ -3,25 +3,25 @@
# Toggles the suspend menu option availability.
# Hybrid: updates state.json and runs env-update for persistence.
STATE_FILE="$HOME/.config/home-manager/state.json"
mkdir -p "$(dirname "$STATE_FILE")"
STATE_DIR="$HOME/.config/nomarchy"
STATE_FILE="$STATE_DIR/state.json"
mkdir -p "$STATE_DIR"
# Initialize if doesn't exist
[[ ! -f $STATE_FILE ]] && echo "{}" > "$STATE_FILE"
# Get current state from env or state file
if [[ $NNOMARCHY_TOGGLE_SUSPEND == "false" ]]; then
if [[ $NOMARCHY_TOGGLE_SUSPEND == "false" ]]; then
NEW_VALUE="true"
notify-send -u low "󰒲 Suspend now available in system menu"
notify-send -u low " Suspend now available in system menu"
else
NEW_VALUE="false"
notify-send -u low "󰒲 Suspend removed from system menu"
notify-send -u low " Suspend removed from system menu"
fi
# Update JSON using jq
# We use a temporary file to avoid corruption if the shell is interrupted
# Update JSON using jq with --argjson for proper boolean handling
TMP_JSON=$(mktemp)
jq ".suspend = $NEW_VALUE" "$STATE_FILE" > "$TMP_JSON" && mv "$TMP_JSON" "$STATE_FILE"
jq --argjson val "$NEW_VALUE" '.suspend = $val' "$STATE_FILE" > "$TMP_JSON" && mv "$TMP_JSON" "$STATE_FILE"
echo "Suspend availability set to $NEW_VALUE. Updating environment..."

View File

@@ -6,7 +6,7 @@ STATE_FILE="/etc/nixos/state.json"
timezone=$(timedatectl list-timezones | gum filter --height 20 --header "Set timezone") || exit 1
sudo jq ".timezone = \"$timezone\"" "$STATE_FILE" > /tmp/state.json && sudo mv /tmp/state.json "$STATE_FILE"
sudo jq --arg tz "$timezone" '.timezone = $tz' "$STATE_FILE" > /tmp/state.json && sudo mv /tmp/state.json "$STATE_FILE"
echo "Timezone is now set to $timezone. Applying changes..."
sudo sys-update