diff --git a/apply-theme.sh b/apply-theme.sh new file mode 100755 index 0000000..78f8093 --- /dev/null +++ b/apply-theme.sh @@ -0,0 +1,210 @@ +#!/bin/bash +# Apply theme colors from ~/.config/colors.conf to all deployed dotfile configs. +# +# Guards: +# - Refuses if any deployed config is symlinked back to ~/Dotfiles (old-style +# install), to prevent theme changes from propagating into the git repo. +# - When configs are copied into ~/.config (new-style install), overwrites +# those copies in-place. +# +# Tracks last-applied state in ~/.config/colors.state so only changed colors +# trigger replacements. Run again after re-install to re-apply your theme. +# +# Usage: ~/apply-theme.sh [/path/to/colors.conf] + +set -euo pipefail + +DOTFILES="${DOTFILES:-$HOME/Dotfiles}" +COLORS_CONF="${1:-$HOME/.config/colors.conf}" +STATE_FILE="$HOME/.config/colors.state" + +# Hardcoded defaults — the values baked into every source file in the repo. +# Used to bootstrap colors.state on first run after a fresh install. +BOOT_TEXT="D6ABAB" +BOOT_BG="1A1A1A" +BOOT_HIGHLIGHT="E40046" +BOOT_DARK="5018DD" +BOOT_RED="F50505" + +# "dotfiles_relative_path|absolute_deployed_path" +USER_FILES=( + "starship.toml|$HOME/.config/starship.toml" + "yazi/theme.toml|$HOME/.config/yazi/theme.toml" + "desktopenvs/hyprland/hypr/hyprland.conf|$HOME/.config/hypr/hyprland.conf" + "desktopenvs/hyprland/hypr/hyprtoolkit.conf|$HOME/.config/hypr/hyprtoolkit.conf" + "desktopenvs/hyprland/hypr/hyprlock.conf|$HOME/.config/hypr/hyprlock.conf" + "desktopenvs/hyprland/kitty/current-theme.conf|$HOME/.config/kitty/current-theme.conf" + "desktopenvs/hyprland/kitty/kitty.conf|$HOME/.config/kitty/kitty.conf" + "desktopenvs/hyprland/kitty/themes/cyberqueer.conf|$HOME/.config/kitty/themes/cyberqueer.conf" + "desktopenvs/hyprland/waybar/style.css|$HOME/.config/waybar/style.css" + "desktopenvs/hyprland/wofi/style.css|$HOME/.config/wofi/style.css" + "desktopenvs/hyprland/walker/themes/cyberqueer.css|$HOME/.config/walker/themes/cyberqueer.css" + "desktopenvs/hyprland/nwg-dock-hyprland/style.css|$HOME/.config/nwg-dock-hyprland/style.css" + "desktopenvs/hyprland/nwg-drawer/drawer.css|$HOME/.config/nwg-drawer/drawer.css" + "desktopenvs/hyprland/nwg-panel/menu-start.css|$HOME/.config/nwg-panel/menu-start.css" + "desktopenvs/hyprland/vicinae/cyberqueer.toml|$HOME/.config/vicinae/cyberqueer.toml" + "desktopenvs/hyprland/scripts/onscreenkb.sh|$HOME/.config/scripts/onscreenkb.sh" + "desktopenvs/hyprland/spicetify/Themes/cli-cyberqueer/color.ini|$HOME/.config/spicetify/Themes/cli-cyberqueer/color.ini" + "desktopenvs/hyprland/spicetify/Themes/matte-cyberqueer/color.ini|$HOME/.config/spicetify/Themes/matte-cyberqueer/color.ini" + "desktopenvs/hyprland/ulauncher/user-themes/cyberqueer/manifest.json|$HOME/.config/ulauncher/user-themes/cyberqueer/manifest.json" + "desktopenvs/hyprland/ulauncher/user-themes/cyberqueer/theme.css|$HOME/.config/ulauncher/user-themes/cyberqueer/theme.css" + "desktopenvs/hyprland/ulauncher/user-themes/cyberqueer/generated.css|$HOME/.config/ulauncher/user-themes/cyberqueer/generated.css" + "desktopenvs/hyprland/Vencord/themes/cyberqueer.theme.css|$HOME/.config/Vencord/themes/cyberqueer.theme.css" + "desktopenvs/hyprland/Vencord/themes/system24/theme/flavors/cyberqueer.theme.css|$HOME/.config/Vencord/themes/system24/theme/flavors/cyberqueer.theme.css" +) + +# System-owned paths — sed is run via sudo +SYS_FILES=( + "etc-ly-config.ini|/etc/ly/config.ini" + "gtk-themes/cyberqueer/gtk-3.0/gtk.css|/usr/share/themes/cyberqueer/gtk-3.0/gtk.css" + "gtk-themes/cyberqueer/gtk-4.0/gtk.css|/usr/share/themes/cyberqueer/gtk-4.0/gtk.css" +) + +# --------------------------------------------------------------------------- + +die() { echo "error: $*" >&2; exit 1; } + +parse_colors() { + local file="$1" + [[ -f "$file" ]] || die "not found: $file" + while IFS='=' read -r key val; do + key="${key%%[[:space:]]*}" + [[ "$key" =~ ^[[:space:]]*# || -z "$key" ]] && continue + val="${val%%#*}" + val="${val//[[:space:]]/}" + val="${val^^}" + printf '%s=%s\n' "$key" "$val" + done < "$file" +} + +# Returns 0 if any path component of $1 is a symlink pointing into DOTFILES +links_into_dotfiles() { + local path="$1" + while [[ "${#path}" -gt 1 ]]; do + if [[ -L "$path" ]]; then + local target + target=$(readlink -f "$path" 2>/dev/null) || break + [[ "$target" == "$DOTFILES"/* || "$target" == "$DOTFILES" ]] && return 0 + fi + [[ "$path" == "$HOME" ]] && break + path=$(dirname "$path") + done + return 1 +} + +# Run sed -i with optional command prefix (e.g. "sudo"). +# Called as: do_replace [sudo] +do_replace() { + local file="$1" + shift # remaining "$@" is either empty or "sudo" + for key in "${CHANGED_KEYS[@]}"; do + local old="${OLD[$key]:-}" + local new="${NEW[$key]}" + [[ -z "$old" || "$old" == "$new" ]] && continue + "$@" sed -i "s/${old}/${new}/gI" "$file" + done +} + +# --------------------------------------------------------------------------- +# Bootstrap state on fresh install (deployed files still have default colors) + +if [[ ! -f "$STATE_FILE" ]]; then + cat > "$STATE_FILE" <