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