#!/usr/bin/env bash set -e # Set the system theme declaratively. # Usage: nomarchy-theme-set [--no-update] THEME_NAME="$1" NO_UPDATE=false if [[ "${2:-}" == "--no-update" ]]; then NO_UPDATE=true fi if [[ -z $THEME_NAME ]]; then echo "Usage: nomarchy-theme-set [--no-update]" exit 1 fi STATE_DIR="$HOME/.config/nomarchy" STATE_FILE="$STATE_DIR/state.json" # Resolve themes directory (Built-in from Nix store via Home Manager, or user extra) if [ -d "$HOME/.config/nomarchy/themes/$THEME_NAME" ]; then THEMES_DIR="$HOME/.config/nomarchy/themes" else THEMES_DIR="$HOME/.local/share/nomarchy/themes" fi mkdir -p "$STATE_DIR" [[ ! -f $STATE_FILE ]] && echo "{}" > "$STATE_FILE" if [ ! -d "$THEMES_DIR/$THEME_NAME" ] && ! [[ "$THEME_NAME" == "nord" ]]; then echo "Theme '$THEME_NAME' not found in $THEMES_DIR" fi TMP_JSON=$(mktemp) jq --arg theme "$THEME_NAME" '.theme = $theme' "$STATE_FILE" > "$TMP_JSON" && mv "$TMP_JSON" "$STATE_FILE" # Sync to system state if we have permissions (for system-level theming like browser policies) SYSTEM_STATE_FILE="/etc/nixos/state.json" if [ -w "$SYSTEM_STATE_FILE" ] || [ -w "/etc/nixos" ]; then sudo jq --arg theme "$THEME_NAME" '.theme = $theme' "$SYSTEM_STATE_FILE" > /tmp/system-state.json 2>/dev/null && sudo mv /tmp/system-state.json "$SYSTEM_STATE_FILE" 2>/dev/null || true fi # Try to find a background for this theme BG_DIR="$THEMES_DIR/$THEME_NAME/backgrounds" if [ -d "$BG_DIR" ]; then BG=$(ls "$BG_DIR" | head -n 1) if [ -n "$BG" ]; then TMP_JSON=$(mktemp) jq --arg wp "$BG_DIR/$BG" '.wallpaper = $wp' "$STATE_FILE" > "$TMP_JSON" && mv "$TMP_JSON" "$STATE_FILE" fi fi echo "Theme set to $THEME_NAME. Applying changes with nomarchy-env-update..." if [[ "$NO_UPDATE" == "true" ]]; then echo "Skipping nomarchy-env-update due to --no-update flag." exit 0 fi nomarchy-env-update nomarchy-theme-set-templates # Run the chain of "tell each app the theme changed" steps. Each step is # optional — the corresponding helper might not be installed, the service # might not be running, the user might not use Obsidian. Skipping is fine; # what we don't want is a step that EXISTS, fails for a real reason, and # leaves the user with a half-applied theme + no idea why. Collect every # real failure into _theme_set_fails and surface them in one notify-send # at the end so the user knows exactly what didn't refresh. _theme_set_fails=() _theme_set_try() { local label="$1"; shift # First arg after label is the command to test for existence. # `systemctl` always exists on a NixOS system, so we let it through # and rely on its own exit code to decide skip vs fail. if [[ "$1" != "systemctl" ]] && ! command -v "$1" >/dev/null 2>&1; then return 0 # not installed → silently skip fi if ! "$@" >/dev/null 2>&1; then _theme_set_fails+=("$label") fi } # Walker reads its CSS via @import of ~/.config/nomarchy/current/theme/apps/walker/style.css, # and waybar's shared fallback style does the same with waybar.css. HM's sd-switch # only restarts services whose unit *definition* changed, so when only the imported # file's contents change, neither gets reloaded. Restart them explicitly. _theme_set_try "Walker" nomarchy-restart-walker _theme_set_try "Waybar" nomarchy-restart-waybar # Hot-reload long-running TUIs / agents that read their colors from # the active-theme symlink and would otherwise stay on the old palette # until the user restarts them by hand. _theme_set_try "btop" nomarchy-restart-btop _theme_set_try "opencode" nomarchy-restart-opencode # Sync palette into Obsidian vaults (no-op when the user has no Obsidian # config or no obsidian.css template in the active theme). _theme_set_try "Obsidian" nomarchy-theme-set-obsidian # Reload the wallpaper — its ExecStart path is stable (~/.config/nomarchy/current/background) # so sd-switch does not detect a unit change when only the symlink target moves. _theme_set_try "wallpaper" systemctl --user restart nomarchy-wallpaper.service if (( ${#_theme_set_fails[@]} > 0 )); then if command -v notify-send >/dev/null 2>&1; then notify-send -u normal "Theme applied with warnings" \ "Did not refresh: $(IFS=', '; echo "${_theme_set_fails[*]}")" fi echo "Warning: failed to refresh: ${_theme_set_fails[*]}" >&2 fi nomarchy-hook theme-set "$THEME_NAME"