Add theme system: local themes, picker, static/dynamic mode
- blob_theme: apply local or shared themes, --dynamic recolors from the current wallpaper without changing it, --print saves the active theme's colors.toml (e.g. for a dynamic palette worth keeping) - themes/: drop-in colors.toml files that install.sh syncs into Omarchy's theme dir, alongside any already-installed themes - ThemePicker widget, walker menu, and Quick Settings tile mirroring the existing wallpaper picker, with color-swatch previews - blob_wallpaper no longer forces dynamic mode on every wallpaper change; it only recolors if you're already in dynamic mode - install.sh: fix a new-directory mkdir bug in backup_and_copy, and stop backing up wallpapers/themes (.bak dirs were showing up as fake entries in the picker) since both are pure git mirrors Claude-Session: https://claude.ai/code/session_011kf23kB9NsaczSYazZsWs6
This commit is contained in:
+104
-34
@@ -1,52 +1,119 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Pull a color theme shared from the wall-styles website and apply it.
|
||||
# Manage color themes: local static themes installed under
|
||||
# ~/.config/omarchy/themes/, the pywal-generated dynamic theme
|
||||
# (blob-dynamic), and themes shared from the wall-styles website.
|
||||
|
||||
THEME_DIR="$HOME/.config/omarchy/themes/blob-dynamic"
|
||||
USER_THEMES_DIR="$HOME/.config/omarchy/themes"
|
||||
CURRENT_DIR="$HOME/.config/omarchy/current"
|
||||
|
||||
# Used only when a bare id is passed instead of a full share link.
|
||||
# Override with: export BLOB_THEME_URL="https://your-deployment.vercel.app"
|
||||
BASE_URL="${BLOB_THEME_URL:-https://wall-styles.vercel.app}"
|
||||
|
||||
if [ -z "$1" ]; then
|
||||
echo "Usage: blob_theme <share-link-or-id>"
|
||||
echo "Example: blob_theme \"https://wall-styles.vercel.app/?id=ab12cd34ef\""
|
||||
exit 1
|
||||
fi
|
||||
slugify() {
|
||||
echo "$1" | tr '[:upper:]' '[:lower:]' | tr ' ' '-'
|
||||
}
|
||||
|
||||
INPUT="$1"
|
||||
current_mode() {
|
||||
local name
|
||||
name=$(cat "$CURRENT_DIR/theme.name" 2>/dev/null)
|
||||
if [ "$name" = "blob-dynamic" ]; then
|
||||
echo "dynamic"
|
||||
else
|
||||
echo "static"
|
||||
fi
|
||||
}
|
||||
|
||||
if [[ "$INPUT" == http*://* ]]; then
|
||||
HOST=$(echo "$INPUT" | sed -E 's#^(https?://[^/]+).*#\1#')
|
||||
ID=$(echo "$INPUT" | grep -oE 'id=[A-Za-z0-9]+' | head -1 | cut -d= -f2)
|
||||
if [ -z "$ID" ]; then
|
||||
echo "Error: no theme id found in link '$INPUT'."
|
||||
theme_exists_locally() {
|
||||
local slug
|
||||
slug=$(slugify "$1")
|
||||
[ -d "$USER_THEMES_DIR/$slug" ] || [ -d "$OMARCHY_PATH/themes/$slug" ]
|
||||
}
|
||||
|
||||
apply_static() {
|
||||
local name="$1"
|
||||
# Clean up a lingering gif-animation daemon from a previous dynamic
|
||||
# wallpaper before switching to a static theme's own background.
|
||||
awww kill --all >/dev/null 2>&1
|
||||
omarchy-theme-set "$name"
|
||||
}
|
||||
|
||||
apply_dynamic() {
|
||||
if [ ! -f "$THEME_DIR/colors.toml" ]; then
|
||||
echo "No dynamic theme yet. Pick a wallpaper first: blob_wallpaper"
|
||||
exit 1
|
||||
fi
|
||||
API="$HOST/api/theme?id=$ID&format=toml"
|
||||
else
|
||||
API="$BASE_URL/api/theme?id=$INPUT&format=toml"
|
||||
fi
|
||||
# Skip the background step: this is purely a recolor of whatever
|
||||
# wallpaper is already showing, not a wallpaper change.
|
||||
OMARCHY_THEME_SKIP_BACKGROUND=1 omarchy-theme-set "blob-dynamic"
|
||||
}
|
||||
|
||||
mkdir -p "$THEME_DIR/backgrounds"
|
||||
case "$1" in
|
||||
"")
|
||||
ags toggle theme-picker
|
||||
;;
|
||||
--menu)
|
||||
omarchy-launch-walker -m menus:blobThemeSelector --width 800 --minheight 400 -p "Select Theme…"
|
||||
;;
|
||||
--mode)
|
||||
current_mode
|
||||
;;
|
||||
--print)
|
||||
CURRENT_COLORS="$CURRENT_DIR/theme/colors.toml"
|
||||
if [ ! -f "$CURRENT_COLORS" ]; then
|
||||
echo "No active theme colors.toml found at $CURRENT_COLORS" >&2
|
||||
exit 1
|
||||
fi
|
||||
# awk always terminates the last line with a newline, even if the
|
||||
# source file doesn't. Omarchy's template engine reads colors.toml
|
||||
# with a bash `while read` loop, which silently drops a final line
|
||||
# missing its newline (e.g. color15) — some built-in themes are
|
||||
# missing it too, so this guards every theme saved via --print.
|
||||
awk '1' "$CURRENT_COLORS"
|
||||
;;
|
||||
--dynamic)
|
||||
apply_dynamic
|
||||
;;
|
||||
*)
|
||||
if theme_exists_locally "$1"; then
|
||||
apply_static "$1"
|
||||
else
|
||||
# Not a local theme: treat it as a wall-styles share link or id.
|
||||
INPUT="$1"
|
||||
|
||||
echo "Fetching theme..."
|
||||
TMP=$(mktemp)
|
||||
if ! curl -fsSL "$API" -o "$TMP"; then
|
||||
echo "Error: could not fetch theme. The link may be expired (themes last one hour)."
|
||||
rm -f "$TMP"
|
||||
exit 1
|
||||
fi
|
||||
if [[ "$INPUT" == http*://* ]]; then
|
||||
HOST=$(echo "$INPUT" | sed -E 's#^(https?://[^/]+).*#\1#')
|
||||
ID=$(echo "$INPUT" | grep -oE 'id=[A-Za-z0-9]+' | head -1 | cut -d= -f2)
|
||||
if [ -z "$ID" ]; then
|
||||
echo "Error: '$INPUT' is not a local theme, and no share id was found in the link."
|
||||
exit 1
|
||||
fi
|
||||
API="$HOST/api/theme?id=$ID&format=toml"
|
||||
else
|
||||
API="$BASE_URL/api/theme?id=$INPUT&format=toml"
|
||||
fi
|
||||
|
||||
if ! grep -q '^background = ' "$TMP"; then
|
||||
echo "Error: the response did not look like a valid colors.toml."
|
||||
rm -f "$TMP"
|
||||
exit 1
|
||||
fi
|
||||
mkdir -p "$THEME_DIR/backgrounds"
|
||||
|
||||
mv "$TMP" "$THEME_DIR/colors.toml"
|
||||
echo "Fetching theme..."
|
||||
TMP=$(mktemp)
|
||||
if ! curl -fsSL "$API" -o "$TMP"; then
|
||||
echo "Error: could not fetch theme, and '$1' is not a local theme name. The link may be expired (themes last one hour)."
|
||||
rm -f "$TMP"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
cat <<EOF > "$THEME_DIR/neovim.lua"
|
||||
if ! grep -q '^background = ' "$TMP"; then
|
||||
echo "Error: the response did not look like a valid colors.toml."
|
||||
rm -f "$TMP"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
mv "$TMP" "$THEME_DIR/colors.toml"
|
||||
|
||||
cat <<EOF > "$THEME_DIR/neovim.lua"
|
||||
return {
|
||||
{
|
||||
"LazyVim/LazyVim",
|
||||
@@ -57,7 +124,10 @@ return {
|
||||
}
|
||||
EOF
|
||||
|
||||
# Apply the Blob-Dynamic theme (reloads waybar, ags, etc.)
|
||||
omarchy-theme-set "blob-dynamic"
|
||||
# Apply the Blob-Dynamic theme (reloads waybar, ags, etc.)
|
||||
omarchy-theme-set "blob-dynamic"
|
||||
|
||||
echo "Applied shared theme to blob-dynamic."
|
||||
echo "Applied shared theme to blob-dynamic."
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
|
||||
@@ -85,10 +85,19 @@ return {
|
||||
}
|
||||
EOF
|
||||
|
||||
# Apply the Blob-Dynamic theme, but skip its own background step: it
|
||||
# Only switch the active color theme to blob-dynamic if you're already
|
||||
# in dynamic mode. The palette above and the background below are kept
|
||||
# up to date regardless, so `blob_theme --dynamic` always reflects the
|
||||
# latest wallpaper — but picking a wallpaper while on a static theme
|
||||
# should change the wallpaper, not silently pull you out of it.
|
||||
#
|
||||
# When it does apply, skip omarchy-theme-set's own background step: it
|
||||
# launches swaybg asynchronously, which races with the gif handling
|
||||
# below and can leave a static swaybg frame on top of an animated gif.
|
||||
OMARCHY_THEME_SKIP_BACKGROUND=1 omarchy-theme-set "blob-dynamic"
|
||||
CURRENT_THEME_NAME=$(cat "$HOME/.config/omarchy/current/theme.name" 2>/dev/null)
|
||||
if [ "$CURRENT_THEME_NAME" = "blob-dynamic" ]; then
|
||||
OMARCHY_THEME_SKIP_BACKGROUND=1 omarchy-theme-set "blob-dynamic"
|
||||
fi
|
||||
|
||||
CURRENT_BACKGROUND_LINK="$HOME/.config/omarchy/current/background"
|
||||
ln -nsf "$THEME_DIR/backgrounds/$(basename "$IMAGE_PATH")" "$CURRENT_BACKGROUND_LINK"
|
||||
|
||||
Reference in New Issue
Block a user