From d2b62c9d6f30a0ea88b2a235cde120cd10ba332b Mon Sep 17 00:00:00 2001 From: Ryan Schanzenbacher Date: Sat, 11 Jul 2026 22:14:43 -0400 Subject: Sketchybar now, got tired of the battery issue --- .../sketchybar/bar-config/plugins/battery.sh | 42 ++++++++++++++++ .../sketchybar/bar-config/plugins/bluetooth.sh | 37 ++++++++++++++ .../sketchybar/bar-config/plugins/brightness.sh | 29 +++++++++++ .../sketchybar/bar-config/plugins/caffeinate.sh | 21 ++++++++ .../modules/sketchybar/bar-config/plugins/clock.sh | 3 ++ .../sketchybar/bar-config/plugins/front_app.sh | 10 ++++ .../modules/sketchybar/bar-config/plugins/mail.sh | 12 +++++ .../sketchybar/bar-config/plugins/network.sh | 45 +++++++++++++++++ .../modules/sketchybar/bar-config/plugins/space.sh | 8 ++++ .../sketchybar/bar-config/plugins/spotify.sh | 20 ++++++++ .../sketchybar/bar-config/plugins/storage.sh | 27 +++++++++++ .../sketchybar/bar-config/plugins/volume.sh | 36 ++++++++++++++ .../sketchybar/bar-config/plugins/weather.sh | 56 ++++++++++++++++++++++ 13 files changed, 346 insertions(+) create mode 100755 users/ryan/modules/sketchybar/bar-config/plugins/battery.sh create mode 100755 users/ryan/modules/sketchybar/bar-config/plugins/bluetooth.sh create mode 100755 users/ryan/modules/sketchybar/bar-config/plugins/brightness.sh create mode 100755 users/ryan/modules/sketchybar/bar-config/plugins/caffeinate.sh create mode 100755 users/ryan/modules/sketchybar/bar-config/plugins/clock.sh create mode 100755 users/ryan/modules/sketchybar/bar-config/plugins/front_app.sh create mode 100755 users/ryan/modules/sketchybar/bar-config/plugins/mail.sh create mode 100755 users/ryan/modules/sketchybar/bar-config/plugins/network.sh create mode 100755 users/ryan/modules/sketchybar/bar-config/plugins/space.sh create mode 100755 users/ryan/modules/sketchybar/bar-config/plugins/spotify.sh create mode 100755 users/ryan/modules/sketchybar/bar-config/plugins/storage.sh create mode 100755 users/ryan/modules/sketchybar/bar-config/plugins/volume.sh create mode 100755 users/ryan/modules/sketchybar/bar-config/plugins/weather.sh (limited to 'users/ryan/modules/sketchybar/bar-config/plugins') diff --git a/users/ryan/modules/sketchybar/bar-config/plugins/battery.sh b/users/ryan/modules/sketchybar/bar-config/plugins/battery.sh new file mode 100755 index 0000000..3d01d63 --- /dev/null +++ b/users/ryan/modules/sketchybar/bar-config/plugins/battery.sh @@ -0,0 +1,42 @@ +#!/usr/bin/env bash +source "$CONFIG_DIR/colors.sh" +source "$CONFIG_DIR/icons.sh" + +CACHE="/tmp/sketchybar_${NAME}.txt" +case "$SENDER" in + mouse.entered) + [ -f "$CACHE" ] && sketchybar --set "$NAME.details" label="$(cat "$CACHE")" + sketchybar --set "$NAME" popup.drawing=on; exit 0 ;; + mouse.exited) + sketchybar --set "$NAME" popup.drawing=off; exit 0 ;; +esac + +RAW="$(pmset -g batt)" +PCT="$(printf '%s' "$RAW" | grep -Eo '[0-9]+%' | head -1 | tr -d '%')" +CHARGING="$(printf '%s' "$RAW" | grep -c 'AC Power')" +[ -z "$PCT" ] && exit 0 + +if [ "$PCT" -ge 80 ]; then ICON=$BAT_4 +elif [ "$PCT" -ge 60 ]; then ICON=$BAT_3 +elif [ "$PCT" -ge 40 ]; then ICON=$BAT_2 +elif [ "$PCT" -ge 20 ]; then ICON=$BAT_1 +else ICON=$BAT_0 +fi + +COLOR=$TEXT +if [ "$CHARGING" -ge 1 ]; then ICON=$BAT_CHARGING; COLOR=$TEXT +elif [ "$PCT" -le 10 ]; then COLOR=$RED +elif [ "$PCT" -le 25 ]; then COLOR=$YELLOW +fi + +sketchybar --set "$NAME" label="${PCT}% ${ICON}" label.color=$COLOR + +# popup: state + time remaining (Waybar battery format-alt "{time}") +STATE="$(printf '%s' "$RAW" | grep -Eo 'discharging|charging|charged|AC attached|finishing charge' | head -1)" +TIME="$(printf '%s' "$RAW" | grep -Eo '[0-9]+:[0-9]+' | head -1)" +LINE="${PCT}%" +[ -n "$STATE" ] && LINE="$LINE · $STATE" +if [ -n "$TIME" ] && [ "$TIME" != "0:00" ]; then + if [ "$CHARGING" -ge 1 ]; then LINE="$LINE · $TIME to full"; else LINE="$LINE · $TIME remaining"; fi +fi +printf '%s' "$LINE" > "$CACHE" diff --git a/users/ryan/modules/sketchybar/bar-config/plugins/bluetooth.sh b/users/ryan/modules/sketchybar/bar-config/plugins/bluetooth.sh new file mode 100755 index 0000000..80185c0 --- /dev/null +++ b/users/ryan/modules/sketchybar/bar-config/plugins/bluetooth.sh @@ -0,0 +1,37 @@ +#!/usr/bin/env bash +source "$CONFIG_DIR/colors.sh" +source "$CONFIG_DIR/icons.sh" + +CACHE="/tmp/sketchybar_${NAME}.txt" +case "$SENDER" in + mouse.entered) + [ -f "$CACHE" ] && sketchybar --set "$NAME.details" label="$(cat "$CACHE")" + sketchybar --set "$NAME" popup.drawing=on; exit 0 ;; + mouse.exited) + sketchybar --set "$NAME" popup.drawing=off; exit 0 ;; +esac + +if ! command -v blueutil >/dev/null 2>&1; then + sketchybar --set "$NAME" label="$BT_OFF" label.color=$TEXT_DIM + printf '%s' "blueutil not installed" > "$CACHE" + exit 0 +fi + +if [ "$1" = "toggle" ]; then + if [ "$(blueutil -p)" = "1" ]; then blueutil -p 0; else blueutil -p 1; fi +fi + +if [ "$(blueutil -p)" = "1" ]; then + NAMES="$(blueutil --connected 2>/dev/null | grep -o 'name: "[^"]*"' | sed 's/name: "//; s/"$//' | paste -sd , - | sed 's/,/, /g')" + COUNT="$(blueutil --connected 2>/dev/null | grep -c 'name:')" + if [ "$COUNT" -gt 0 ]; then + sketchybar --set "$NAME" label="$BT_CONNECTED" label.color=$TEXT + printf '%s' "Bluetooth on · $COUNT connected: $NAMES" > "$CACHE" + else + sketchybar --set "$NAME" label="$BT_ON" label.color=$TEXT + printf '%s' "Bluetooth on · no devices connected" > "$CACHE" + fi +else + sketchybar --set "$NAME" label="$BT_OFF" label.color=$TEXT_DIM + printf '%s' "Bluetooth off" > "$CACHE" +fi diff --git a/users/ryan/modules/sketchybar/bar-config/plugins/brightness.sh b/users/ryan/modules/sketchybar/bar-config/plugins/brightness.sh new file mode 100755 index 0000000..87a245f --- /dev/null +++ b/users/ryan/modules/sketchybar/bar-config/plugins/brightness.sh @@ -0,0 +1,29 @@ +#!/usr/bin/env bash +# backlight -> brightness. Requires the `brightness` CLI (brew install brightness). +# NOTE: reading/writing internal-display brightness is unreliable on Apple Silicon; +# the item hides itself if the tool or a readable value is unavailable. +source "$CONFIG_DIR/colors.sh" +source "$CONFIG_DIR/icons.sh" + +command -v brightness >/dev/null 2>&1 || { sketchybar --set "$NAME" drawing=off; exit 0; } + +read_val() { brightness -l 2>/dev/null | awk '/display 0: brightness/{print $NF}'; } + +if [ "$SENDER" = "mouse.scrolled" ] && command -v bc >/dev/null 2>&1; then + CUR="$(read_val)" + if [ -n "$CUR" ]; then + case "$INFO" in + -*) brightness "$(echo "$CUR - 0.05" | bc)" 2>/dev/null ;; # scroll down + *) brightness "$(echo "$CUR + 0.05" | bc)" 2>/dev/null ;; # scroll up + esac + fi +fi + +CUR="$(read_val)" +[ -z "$CUR" ] && { sketchybar --set "$NAME" drawing=off; exit 0; } +PCT="$(printf '%.0f' "$(echo "$CUR * 100" | bc -l 2>/dev/null)" 2>/dev/null)" +[ -z "$PCT" ] && PCT=0 + +if [ "$PCT" -ge 50 ]; then ICON=$BL_HIGH; else ICON=$BL_LOW; fi +# Waybar: {percent}% {icon} +sketchybar --set "$NAME" drawing=on label="${PCT}% ${ICON}" diff --git a/users/ryan/modules/sketchybar/bar-config/plugins/caffeinate.sh b/users/ryan/modules/sketchybar/bar-config/plugins/caffeinate.sh new file mode 100755 index 0000000..ce4c4d2 --- /dev/null +++ b/users/ryan/modules/sketchybar/bar-config/plugins/caffeinate.sh @@ -0,0 +1,21 @@ +#!/usr/bin/env bash +# idle_inhibitor -> caffeinate (keeps display + system awake while "activated") +source "$CONFIG_DIR/colors.sh" +source "$CONFIG_DIR/icons.sh" + +PIDFILE="/tmp/sketchybar_caffeinate.pid" +is_on() { [ -f "$PIDFILE" ] && kill -0 "$(cat "$PIDFILE")" 2>/dev/null; } + +if [ "$1" = "toggle" ]; then + if is_on; then + kill "$(cat "$PIDFILE")" 2>/dev/null; rm -f "$PIDFILE" + else + caffeinate -d -i -s & echo $! > "$PIDFILE" + fi +fi + +if is_on; then + sketchybar --set "$NAME" label="$IDLE_ON" label.color=$TEXT # activated +else + sketchybar --set "$NAME" label="$IDLE_OFF" label.color=$TEXT_DIM # deactivated +fi diff --git a/users/ryan/modules/sketchybar/bar-config/plugins/clock.sh b/users/ryan/modules/sketchybar/bar-config/plugins/clock.sh new file mode 100755 index 0000000..e78ee89 --- /dev/null +++ b/users/ryan/modules/sketchybar/bar-config/plugins/clock.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +# Waybar: {:%a %d %b %H:%M:%S} +sketchybar --set "$NAME" label="$(date '+%a %d %b %H:%M:%S')" diff --git a/users/ryan/modules/sketchybar/bar-config/plugins/front_app.sh b/users/ryan/modules/sketchybar/bar-config/plugins/front_app.sh new file mode 100755 index 0000000..c5d8ed0 --- /dev/null +++ b/users/ryan/modules/sketchybar/bar-config/plugins/front_app.sh @@ -0,0 +1,10 @@ +#!/usr/bin/env bash +# hyprland/window -> focused application name. +# (For the literal window *title* instead of the app name, query yabai: +# yabai -m query --windows --window | jq -r '.title') +source "$CONFIG_DIR/colors.sh" +source "$CONFIG_DIR/icons.sh" + +if [ "$SENDER" = "front_app_switched" ]; then + sketchybar --set "$NAME" label="$INFO" +fi diff --git a/users/ryan/modules/sketchybar/bar-config/plugins/mail.sh b/users/ryan/modules/sketchybar/bar-config/plugins/mail.sh new file mode 100755 index 0000000..7ce2fe6 --- /dev/null +++ b/users/ryan/modules/sketchybar/bar-config/plugins/mail.sh @@ -0,0 +1,12 @@ +#!/usr/bin/env bash +# Waybar used a custom mail.py; here we read Mail.app's unread inbox count. +# (First run may prompt for Automation permission. Swap this for your provider.) +source "$HOME/.config/sketchybar/icons.sh" + +UNREAD="$(osascript -e 'tell application "Mail" to get unread count of inbox' 2>/dev/null)" + +if [ -n "$UNREAD" ] && [ "$UNREAD" -gt 0 ] 2>/dev/null; then + sketchybar --set "$NAME" label="$MAIL $UNREAD" +else + sketchybar --set "$NAME" label="$MAIL" +fi diff --git a/users/ryan/modules/sketchybar/bar-config/plugins/network.sh b/users/ryan/modules/sketchybar/bar-config/plugins/network.sh new file mode 100755 index 0000000..b6b003a --- /dev/null +++ b/users/ryan/modules/sketchybar/bar-config/plugins/network.sh @@ -0,0 +1,45 @@ +#!/usr/bin/env bash +source "$CONFIG_DIR/colors.sh" +source "$CONFIG_DIR/icons.sh" + +CACHE="/tmp/sketchybar_${NAME}.txt" +case "$SENDER" in + mouse.entered) + [ -f "$CACHE" ] && sketchybar --set "$NAME.details" label="$(cat "$CACHE")" + sketchybar --set "$NAME" popup.drawing=on; exit 0 ;; + mouse.exited) + sketchybar --set "$NAME" popup.drawing=off; exit 0 ;; +esac + +SERVICE="$(route -n get default 2>/dev/null | awk '/interface:/{print $2}')" +IP="$(ipconfig getifaddr "$SERVICE" 2>/dev/null)" + +if [ -z "$IP" ]; then + sketchybar --set "$NAME" label="$NET_OFF" + printf '%s' "Disconnected" > "$CACHE" + exit 0 +fi + +WIFI_DEV="$(networksetup -listallhardwareports 2>/dev/null | awk '/Wi-Fi/{getline; print $2}')" +if [ "$SERVICE" = "$WIFI_DEV" ]; then ICON=$WIFI_4; TYPE="Wi-Fi"; else ICON=$ETHERNET; TYPE="Ethernet"; fi + +sketchybar --set "$NAME" label="$IP $ICON" + +# ---- popup details: interface, ip/cidr, gateway, SSID ---- +MASK="$(ifconfig "$SERVICE" 2>/dev/null | awk '/inet /{print $4; exit}')" +CIDR="" +if [ -n "$MASK" ]; then + n=$(( MASK )); c=0 + while [ "$n" -gt 0 ]; do c=$(( c + (n & 1) )); n=$(( n >> 1 )); done + CIDR="$c" +fi +GW="$(route -n get default 2>/dev/null | awk '/gateway:/{print $2}')" +SSID="" +if [ "$TYPE" = "Wi-Fi" ]; then + SSID="$(networksetup -getairportnetwork "$SERVICE" 2>/dev/null | sed -n 's/^Current Wi-Fi Network: //p')" +fi + +LINE="$SERVICE · $TYPE · ${IP}${CIDR:+/$CIDR}" +[ -n "$GW" ] && LINE="$LINE · gw $GW" +[ -n "$SSID" ] && LINE="$LINE · $SSID" +printf '%s' "$LINE" > "$CACHE" diff --git a/users/ryan/modules/sketchybar/bar-config/plugins/space.sh b/users/ryan/modules/sketchybar/bar-config/plugins/space.sh new file mode 100755 index 0000000..f15ecca --- /dev/null +++ b/users/ryan/modules/sketchybar/bar-config/plugins/space.sh @@ -0,0 +1,8 @@ +#!/usr/bin/env bash +# hyprland/workspaces active/visible -> highlighted (white) icon. +# Waybar's 3px white top-border on the active button maps to icon.highlight here. +if [ "$SELECTED" = "true" ]; then + sketchybar --set "$NAME" icon.highlight=on +else + sketchybar --set "$NAME" icon.highlight=off +fi diff --git a/users/ryan/modules/sketchybar/bar-config/plugins/spotify.sh b/users/ryan/modules/sketchybar/bar-config/plugins/spotify.sh new file mode 100755 index 0000000..8d91297 --- /dev/null +++ b/users/ryan/modules/sketchybar/bar-config/plugins/spotify.sh @@ -0,0 +1,20 @@ +#!/usr/bin/env bash +# custom/spotify -> now playing, driven by the native media_change event. +source "$HOME/.config/sketchybar/icons.sh" + +# Waybar on-click: playerctl play-pause +if [ "$1" = "toggle" ]; then + osascript -e 'tell application "Spotify" to playpause' 2>/dev/null + exit 0 +fi + +STATE="$(printf '%s' "$INFO" | sed -nE 's/.*"state":"([^"]*)".*/\1/p')" +TITLE="$(printf '%s' "$INFO" | sed -nE 's/.*"title":"([^"]*)".*/\1/p')" +ARTIST="$(printf '%s' "$INFO" | sed -nE 's/.*"artist":"([^"]*)".*/\1/p')" + +# exec-if check-for-music -> only draw while something is playing +if [ "$STATE" = "playing" ] && [ -n "$TITLE" ]; then + sketchybar --set "$NAME" drawing=on label="$TITLE - $ARTIST" +else + sketchybar --set "$NAME" drawing=off +fi diff --git a/users/ryan/modules/sketchybar/bar-config/plugins/storage.sh b/users/ryan/modules/sketchybar/bar-config/plugins/storage.sh new file mode 100755 index 0000000..b844bb5 --- /dev/null +++ b/users/ryan/modules/sketchybar/bar-config/plugins/storage.sh @@ -0,0 +1,27 @@ +#!/usr/bin/env bash +source "$CONFIG_DIR/colors.sh" +source "$CONFIG_DIR/icons.sh" + +CACHE="/tmp/sketchybar_${NAME}.txt" +case "$SENDER" in + mouse.entered) + [ -f "$CACHE" ] && sketchybar --set "$NAME.details" label="$(cat "$CACHE")" + sketchybar --set "$NAME" popup.drawing=on; exit 0 ;; + mouse.exited) + sketchybar --set "$NAME" popup.drawing=off; exit 0 ;; +esac + +# On APFS the real user usage lives on the Data volume; fall back to / +VOL="/System/Volumes/Data"; [ -d "$VOL" ] || VOL="/" + +DF="$(df -h "$VOL" | awk 'NR==2{gsub("%","",$5); print $2, $3, $4, $5}')" +set -- $DF; SIZE="$1"; USED="$2"; AVAIL="$3"; PCT="$4" +[ -z "$PCT" ] && exit 0 + +COLOR=$TEXT +if [ "$PCT" -ge 90 ]; then COLOR=$RED # custom-storage.critical +elif [ "$PCT" -ge 80 ]; then COLOR=$YELLOW # custom-storage.warning +fi + +sketchybar --set "$NAME" label="${PCT}% ${DISK}" label.color=$COLOR +printf '%s' "Disk · ${USED} used of ${SIZE} (${PCT}%) · ${AVAIL} free" > "$CACHE" diff --git a/users/ryan/modules/sketchybar/bar-config/plugins/volume.sh b/users/ryan/modules/sketchybar/bar-config/plugins/volume.sh new file mode 100755 index 0000000..667d0e8 --- /dev/null +++ b/users/ryan/modules/sketchybar/bar-config/plugins/volume.sh @@ -0,0 +1,36 @@ +#!/usr/bin/env bash +source "$CONFIG_DIR/colors.sh" +source "$CONFIG_DIR/icons.sh" + +STEP=5 # % per scroll tick (Waybar used scroll-step: 1 — bump this down to taste) + +if [ "$SENDER" = "mouse.scrolled" ]; then + CUR="$(osascript -e 'output volume of (get volume settings)')" + case "$SCROLL_DELTA" in + -*) VOL=$(( CUR - STEP )) ;; # scroll down + *) VOL=$(( CUR + STEP )) ;; # scroll up + esac + [ "$VOL" -lt 0 ] && VOL=0 + [ "$VOL" -gt 100 ] && VOL=100 + osascript -e "set volume output volume $VOL" +elif [ "$SENDER" = "volume_change" ]; then + VOL="$INFO" +else + VOL="$(osascript -e 'output volume of (get volume settings)')" +fi + +MUTED="$(osascript -e 'output muted of (get volume settings)')" + +if [ "$MUTED" = "true" ] || { [ "$VOL" -eq 0 ] 2>/dev/null; }; then + sketchybar --set "$NAME" label="$VOL_MUTE" # format-muted + exit 0 +fi + +if [ "$VOL" -ge 66 ]; then ICON=$VOL_3 +elif [ "$VOL" -ge 33 ]; then ICON=$VOL_2 +elif [ "$VOL" -ge 1 ]; then ICON=$VOL_1 +else ICON=$VOL_0 +fi + +# Waybar: {volume} {icon} +sketchybar --set "$NAME" label="$VOL $ICON" diff --git a/users/ryan/modules/sketchybar/bar-config/plugins/weather.sh b/users/ryan/modules/sketchybar/bar-config/plugins/weather.sh new file mode 100755 index 0000000..abf8103 --- /dev/null +++ b/users/ryan/modules/sketchybar/bar-config/plugins/weather.sh @@ -0,0 +1,56 @@ +#!/usr/bin/env bash +# custom/weather -> condition icon + temp, with a hover popup ("tooltip"). +# Uses wttr.in JSON (format=j2, the smaller no-hourly variant). Needs jq + curl. +source "$CONFIG_DIR/colors.sh" +source "$CONFIG_DIR/icons.sh" + +CACHE="/tmp/sketchybar_weather.txt" + +# --- hover: show/hide the popup, populated from the cached line --- +case "$SENDER" in + mouse.entered) + [ -f "$CACHE" ] && sketchybar --set weather.details label="$(cat "$CACHE")" + sketchybar --set "$NAME" popup.drawing=on + exit 0 ;; + mouse.exited) + sketchybar --set "$NAME" popup.drawing=off + exit 0 ;; +esac + +command -v jq >/dev/null 2>&1 || { sketchybar --set "$NAME" label="wttr?"; exit 0; } + +JSON="$(curl -sf --max-time 6 'wttr.in/?format=j2')" \ + || JSON="$(curl -sf --max-time 6 'wttr.in/?format=j1')" \ + || { sketchybar --set "$NAME" label="--"; exit 0; } + +cc() { printf '%s' "$JSON" | jq -r ".current_condition[0].$1 // empty"; } +CODE="$(cc weatherCode)"; TEMP="$(cc temp_F)"; FEELS="$(cc FeelsLikeF)" +HUM="$(cc humidity)"; WSPD="$(cc windspeedMiles)"; WDIR="$(cc winddir16Point)" +DESC="$(printf '%s' "$JSON" | jq -r '.current_condition[0].weatherDesc[0].value // empty')" +AREA="$(printf '%s' "$JSON" | jq -r '.nearest_area[0].areaName[0].value // empty')" + +# daytime? simple local-hour heuristic (06:00–18:59) for clear/partly-cloudy variants +HOUR=$(date +%H); HOUR=${HOUR#0}; : "${HOUR:=0}" +if [ "$HOUR" -ge 6 ] && [ "$HOUR" -lt 19 ]; then DAY=1; else DAY=0; fi + +# WWO weatherCode -> nf-weather glyph +case "$CODE" in + 113) [ "$DAY" = 1 ] && ICON="$WEA_SUNNY" || ICON="$WEA_NIGHT" ;; + 116) [ "$DAY" = 1 ] && ICON="$WEA_DAY_CLOUDY" || ICON="$WEA_NIGHT_CLOUDY" ;; + 119|122) ICON="$WEA_CLOUDY" ;; + 143|248|260) ICON="$WEA_FOG" ;; + 200|386|389|392|395) ICON="$WEA_THUNDER" ;; + 176|263|266|293|296|353) ICON="$WEA_SHOWERS" ;; + 299|302|305|308|356|359) ICON="$WEA_RAIN" ;; + 179|227|230|323|326|329|332|335|338|368|371) ICON="$WEA_SNOW" ;; + 182|185|281|284|311|314|317|320|350|362|365|374|377) ICON="$WEA_SLEET" ;; + *) ICON="$WEA_CLOUDY" ;; +esac + +[ -z "$TEMP" ] && exit 0 + +# bar: °F (drop " ${TEMP}°F" if you want the icon only) +sketchybar --set "$NAME" label="$ICON ${TEMP}°F" + +# cache the single-line hover tooltip +printf '%s' "${AREA:+$AREA · }${DESC} · feels ${FEELS}°F · ${HUM}% humidity · ${WDIR} ${WSPD}mph" > "$CACHE" -- cgit v1.3