aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRyan Schanzenbacher <ryan@rschanz.org>2026-07-11 22:14:43 -0400
committerRyan Schanzenbacher <ryan@rschanz.org>2026-07-11 22:14:43 -0400
commitd2b62c9d6f30a0ea88b2a235cde120cd10ba332b (patch)
treef373003e64c3ec4593d7ae4ffac72de52767aa70
parent27117202739f092d837af2752e4b9801c47b8ddb (diff)
Sketchybar now, got tired of the battery issue
-rw-r--r--hosts/RyanMac/configuration.nix2
-rw-r--r--modules/darwin/random-wallpaper/default.nix (renamed from modules/darwin/random-wallpaper/module.nix)0
-rw-r--r--users/ryan/home.nix5
-rw-r--r--users/ryan/modules/sketchybar/bar-config/README.md63
-rw-r--r--users/ryan/modules/sketchybar/bar-config/colors.sh11
-rw-r--r--users/ryan/modules/sketchybar/bar-config/icons.sh35
-rwxr-xr-xusers/ryan/modules/sketchybar/bar-config/plugins/battery.sh42
-rwxr-xr-xusers/ryan/modules/sketchybar/bar-config/plugins/bluetooth.sh37
-rwxr-xr-xusers/ryan/modules/sketchybar/bar-config/plugins/brightness.sh29
-rwxr-xr-xusers/ryan/modules/sketchybar/bar-config/plugins/caffeinate.sh21
-rwxr-xr-xusers/ryan/modules/sketchybar/bar-config/plugins/clock.sh3
-rwxr-xr-xusers/ryan/modules/sketchybar/bar-config/plugins/front_app.sh10
-rwxr-xr-xusers/ryan/modules/sketchybar/bar-config/plugins/mail.sh12
-rwxr-xr-xusers/ryan/modules/sketchybar/bar-config/plugins/network.sh45
-rwxr-xr-xusers/ryan/modules/sketchybar/bar-config/plugins/space.sh8
-rwxr-xr-xusers/ryan/modules/sketchybar/bar-config/plugins/spotify.sh20
-rwxr-xr-xusers/ryan/modules/sketchybar/bar-config/plugins/storage.sh27
-rwxr-xr-xusers/ryan/modules/sketchybar/bar-config/plugins/volume.sh36
-rwxr-xr-xusers/ryan/modules/sketchybar/bar-config/plugins/weather.sh56
-rwxr-xr-xusers/ryan/modules/sketchybar/bar-config/sketchybarrc172
-rw-r--r--users/ryan/modules/sketchybar/default.nix19
21 files changed, 649 insertions, 4 deletions
diff --git a/hosts/RyanMac/configuration.nix b/hosts/RyanMac/configuration.nix
index f72c6aa..e5b38ca 100644
--- a/hosts/RyanMac/configuration.nix
+++ b/hosts/RyanMac/configuration.nix
@@ -45,7 +45,7 @@ in {
45 # Modules 45 # Modules
46 imports = [ 46 imports = [
47 inputs.nix-homebrew.darwinModules.nix-homebrew 47 inputs.nix-homebrew.darwinModules.nix-homebrew
48 ../../modules/darwin/random-wallpaper/module.nix 48 ../../modules/darwin/random-wallpaper
49 ]; 49 ];
50 50
51 # Define the system's user and home dir location 51 # Define the system's user and home dir location
diff --git a/modules/darwin/random-wallpaper/module.nix b/modules/darwin/random-wallpaper/default.nix
index b20ce88..b20ce88 100644
--- a/modules/darwin/random-wallpaper/module.nix
+++ b/modules/darwin/random-wallpaper/default.nix
diff --git a/users/ryan/home.nix b/users/ryan/home.nix
index 2aaacb3..1c77723 100644
--- a/users/ryan/home.nix
+++ b/users/ryan/home.nix
@@ -15,9 +15,7 @@
15 15
16 # My own modules 16 # My own modules
17 ryan.neovim.enable = true; 17 ryan.neovim.enable = true;
18 ryan.simple-bar.enable = pkgs.stdenv.isDarwin; 18 ryan.sketchybar.enable = true;
19 ryan.taskwarrior-widget.enable = pkgs.stdenv.isDarwin;
20 ryan.ubersicht.enable = pkgs.stdenv.isDarwin;
21 19
22 programs.starship = { 20 programs.starship = {
23 enable = true; 21 enable = true;
@@ -148,6 +146,7 @@
148 audacity 146 audacity
149 ffmpeg 147 ffmpeg
150 blender 148 blender
149 nerd-fonts.anonymice
151 ]; 150 ];
152 151
153 # Home Manager is pretty good at managing dotfiles. The primary way to manage 152 # Home Manager is pretty good at managing dotfiles. The primary way to manage
diff --git a/users/ryan/modules/sketchybar/bar-config/README.md b/users/ryan/modules/sketchybar/bar-config/README.md
new file mode 100644
index 0000000..7b1bf97
--- /dev/null
+++ b/users/ryan/modules/sketchybar/bar-config/README.md
@@ -0,0 +1,63 @@
1# SketchyBar config (translated from Waybar)
2
3This is a translation of a Hyprland/Waybar setup (`config` + `style.css`) into an
4equivalent [SketchyBar](https://github.com/FelixKratz/SketchyBar) config for macOS.
5Layout, fonts, and colours mirror the originals as closely as macOS allows.
6
7## Install
8
9```sh
10# 1. SketchyBar + the font your CSS references
11brew tap FelixKratz/formulae
12brew install sketchybar
13brew install --cask font-anonymice-nerd-font # "AnonymicePro Nerd Font"
14
15# 2. Drop these files in place
16cp -r .config/sketchybar ~/.config/ # (or move this folder there)
17chmod +x ~/.config/sketchybar/sketchybarrc ~/.config/sketchybar/plugins/*.sh
18
19# 3. Start it
20brew services start sketchybar
21```
22
23## Optional dependencies (items self-hide / degrade gracefully without them)
24
25| Item | Needs | Install |
26|-------------|--------------------------------|---------------------------------|
27| workspaces | yabai (tiling WM) for `space` | `brew install koekeishiya/formulae/yabai` |
28| bluetooth | `blueutil` | `brew install blueutil` |
29| brightness | `brightness` CLI | `brew install brightness` |
30| weather | `curl` (built in) | — |
31
32> **Spaces / yabai:** the `space` component needs yabai, which needs SIP partially
33> disabled. If you'd rather not touch SIP, [AeroSpace](https://github.com/nikitabobko/AeroSpace)
34> is a SIP-free tiling WM — swap the `space` loop for its `aerospace_workspace_change`
35> event and point `click_script` at `aerospace workspace $sid`.
36
37## Module mapping
38
39| Waybar | SketchyBar | Notes |
40|-----------------------|-----------------------------------|-------|
41| hyprland/workspaces | `space` items (yabai) | number icon, dim→white for active (Waybar's 3px top-border → `icon.highlight`) |
42| hyprland/window | `front_app` | shows app name; window *title* needs a yabai query (noted in plugin) |
43| clock | `clock` | same `%a %d %b %H:%M` format |
44| battery (BAT0) | `battery` | `pmset`; same icons, warning@25 / critical@10, charging bolt |
45| bluetooth | `bluetooth` | `blueutil`; on/off/connected glyphs, click toggles power |
46| network | `network` | ip + wifi/ethernet/off glyph (cidr & RSSI dropped — not exposed on macOS) |
47| pulseaudio | `volume` | native `volume_change`; volume% + icon, mute glyph |
48| backlight | `brightness` | `brightness` CLI; scroll to adjust (flaky on Apple Silicon) |
49| custom/storage | `storage` | `df /`; warning@80 / critical@90 |
50| custom/weather | `weather` | `wttr.in` in °F, click opens wttr.in |
51| custom/mail | `mail` | Mail.app unread count (swap for your provider) |
52| custom/spotify | `spotify` | native `media_change`; title–artist, click play/pause |
53| idle_inhibitor | `caffeinate` | click toggles `caffeinate`; lock/unlock glyphs |
54
55## Omitted (no macOS/SketchyBar equivalent)
56
57- **tray** — the macOS menu bar already renders status/menu-extra icons.
58- **privacy** (screenshare/mic) — macOS shows camera/mic indicators natively.
59- **hyprland/submap** — yabai has no submap concept.
60- **battery#num2** (BAT1) — Macs have a single battery.
61
62Colours in `colors.sh` and glyphs in `icons.sh` are taken verbatim from your
63`style.css` and `config` (glyphs are byte-for-byte identical).
diff --git a/users/ryan/modules/sketchybar/bar-config/colors.sh b/users/ryan/modules/sketchybar/bar-config/colors.sh
new file mode 100644
index 0000000..1ef1264
--- /dev/null
+++ b/users/ryan/modules/sketchybar/bar-config/colors.sh
@@ -0,0 +1,11 @@
1#!/usr/bin/env bash
2# Colors translated from style.css (0xAARRGGBB)
3
4export WHITE=0xffffffff
5export TEXT=0xffd9d8d8 # rgba(217,216,216,1) default text / visible+active workspace
6export TEXT_DIM=0x66d9d8d8 # rgba(217,216,216,0.4) inactive workspace
7export RED=0xffee2e24 # rgba(238,46,36,1) urgent / battery+storage critical
8export YELLOW=0xffffd204 # rgba(255,210,4,1) battery+storage warning
9export BAR_COLOR=0x80000000 # rgba(0,0,0,0.25) #waybar background
10export POPUP_BG=0xd9231f20 # rgba(35,31,32,0.85) window#waybar.solo background
11export TRANSPARENT=0x00000000
diff --git a/users/ryan/modules/sketchybar/bar-config/icons.sh b/users/ryan/modules/sketchybar/bar-config/icons.sh
new file mode 100644
index 0000000..39de9cd
--- /dev/null
+++ b/users/ryan/modules/sketchybar/bar-config/icons.sh
@@ -0,0 +1,35 @@
1#!/usr/bin/env bash
2# Nerd Font glyphs, byte-for-byte identical to the original Waybar config.
3# Font: AnonymicePro Nerd Font
4
5# battery format-icons (low -> high) + charging
6export BAT_0="󰁺"; export BAT_1="󰁻"; export BAT_2="󰁾"
7export BAT_3="󰂀"; export BAT_4="󰁹"; export BAT_CHARGING="󰂄"
8
9# bluetooth
10export BT_ON="󰂯"; export BT_OFF="󰂲"; export BT_CONNECTED="󰂱"
11
12# network (wifi weak -> strong, ethernet, disconnected)
13export WIFI_1="󰤟"; export WIFI_2="󰤢"; export WIFI_3="󰤥"
14export WIFI_4="󰤨"; export ETHERNET=""; export NET_OFF="󰤭"
15
16# pulseaudio / volume (default set) + muted
17export VOL_0=""; export VOL_1=""; export VOL_2=""
18export VOL_3=""; export VOL_MUTE=""
19
20# backlight / brightness (dim, bright)
21export BL_LOW=""; export BL_HIGH=""
22
23# idle_inhibitor (activated=lock, deactivated=unlock)
24export IDLE_ON=""; export IDLE_OFF=""
25
26# misc
27export DISK=""; export MAIL=""; export SPOTIFY=""
28
29# weather (nf-weather-*, wttr.in weatherCode -> glyph)
30export WEA_SUNNY=""; export WEA_NIGHT=""
31export WEA_DAY_CLOUDY=""; export WEA_NIGHT_CLOUDY=""
32export WEA_CLOUDY=""; export WEA_FOG=""
33export WEA_SHOWERS=""; export WEA_RAIN=""
34export WEA_SNOW=""; export WEA_SLEET=""
35export WEA_THUNDER=""
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
2source "$CONFIG_DIR/colors.sh"
3source "$CONFIG_DIR/icons.sh"
4
5CACHE="/tmp/sketchybar_${NAME}.txt"
6case "$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 ;;
12esac
13
14RAW="$(pmset -g batt)"
15PCT="$(printf '%s' "$RAW" | grep -Eo '[0-9]+%' | head -1 | tr -d '%')"
16CHARGING="$(printf '%s' "$RAW" | grep -c 'AC Power')"
17[ -z "$PCT" ] && exit 0
18
19if [ "$PCT" -ge 80 ]; then ICON=$BAT_4
20elif [ "$PCT" -ge 60 ]; then ICON=$BAT_3
21elif [ "$PCT" -ge 40 ]; then ICON=$BAT_2
22elif [ "$PCT" -ge 20 ]; then ICON=$BAT_1
23else ICON=$BAT_0
24fi
25
26COLOR=$TEXT
27if [ "$CHARGING" -ge 1 ]; then ICON=$BAT_CHARGING; COLOR=$TEXT
28elif [ "$PCT" -le 10 ]; then COLOR=$RED
29elif [ "$PCT" -le 25 ]; then COLOR=$YELLOW
30fi
31
32sketchybar --set "$NAME" label="${PCT}% ${ICON}" label.color=$COLOR
33
34# popup: state + time remaining (Waybar battery format-alt "{time}")
35STATE="$(printf '%s' "$RAW" | grep -Eo 'discharging|charging|charged|AC attached|finishing charge' | head -1)"
36TIME="$(printf '%s' "$RAW" | grep -Eo '[0-9]+:[0-9]+' | head -1)"
37LINE="${PCT}%"
38[ -n "$STATE" ] && LINE="$LINE · $STATE"
39if [ -n "$TIME" ] && [ "$TIME" != "0:00" ]; then
40 if [ "$CHARGING" -ge 1 ]; then LINE="$LINE · $TIME to full"; else LINE="$LINE · $TIME remaining"; fi
41fi
42printf '%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
2source "$CONFIG_DIR/colors.sh"
3source "$CONFIG_DIR/icons.sh"
4
5CACHE="/tmp/sketchybar_${NAME}.txt"
6case "$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 ;;
12esac
13
14if ! 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
18fi
19
20if [ "$1" = "toggle" ]; then
21 if [ "$(blueutil -p)" = "1" ]; then blueutil -p 0; else blueutil -p 1; fi
22fi
23
24if [ "$(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
34else
35 sketchybar --set "$NAME" label="$BT_OFF" label.color=$TEXT_DIM
36 printf '%s' "Bluetooth off" > "$CACHE"
37fi
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.
5source "$CONFIG_DIR/colors.sh"
6source "$CONFIG_DIR/icons.sh"
7
8command -v brightness >/dev/null 2>&1 || { sketchybar --set "$NAME" drawing=off; exit 0; }
9
10read_val() { brightness -l 2>/dev/null | awk '/display 0: brightness/{print $NF}'; }
11
12if [ "$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
20fi
21
22CUR="$(read_val)"
23[ -z "$CUR" ] && { sketchybar --set "$NAME" drawing=off; exit 0; }
24PCT="$(printf '%.0f' "$(echo "$CUR * 100" | bc -l 2>/dev/null)" 2>/dev/null)"
25[ -z "$PCT" ] && PCT=0
26
27if [ "$PCT" -ge 50 ]; then ICON=$BL_HIGH; else ICON=$BL_LOW; fi
28# Waybar: {percent}% {icon}
29sketchybar --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")
3source "$CONFIG_DIR/colors.sh"
4source "$CONFIG_DIR/icons.sh"
5
6PIDFILE="/tmp/sketchybar_caffeinate.pid"
7is_on() { [ -f "$PIDFILE" ] && kill -0 "$(cat "$PIDFILE")" 2>/dev/null; }
8
9if [ "$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
15fi
16
17if is_on; then
18 sketchybar --set "$NAME" label="$IDLE_ON" label.color=$TEXT # activated
19else
20 sketchybar --set "$NAME" label="$IDLE_OFF" label.color=$TEXT_DIM # deactivated
21fi
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}
3sketchybar --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')
5source "$CONFIG_DIR/colors.sh"
6source "$CONFIG_DIR/icons.sh"
7
8if [ "$SENDER" = "front_app_switched" ]; then
9 sketchybar --set "$NAME" label="$INFO"
10fi
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.)
4source "$HOME/.config/sketchybar/icons.sh"
5
6UNREAD="$(osascript -e 'tell application "Mail" to get unread count of inbox' 2>/dev/null)"
7
8if [ -n "$UNREAD" ] && [ "$UNREAD" -gt 0 ] 2>/dev/null; then
9 sketchybar --set "$NAME" label="$MAIL $UNREAD"
10else
11 sketchybar --set "$NAME" label="$MAIL"
12fi
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
2source "$CONFIG_DIR/colors.sh"
3source "$CONFIG_DIR/icons.sh"
4
5CACHE="/tmp/sketchybar_${NAME}.txt"
6case "$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 ;;
12esac
13
14SERVICE="$(route -n get default 2>/dev/null | awk '/interface:/{print $2}')"
15IP="$(ipconfig getifaddr "$SERVICE" 2>/dev/null)"
16
17if [ -z "$IP" ]; then
18 sketchybar --set "$NAME" label="$NET_OFF"
19 printf '%s' "Disconnected" > "$CACHE"
20 exit 0
21fi
22
23WIFI_DEV="$(networksetup -listallhardwareports 2>/dev/null | awk '/Wi-Fi/{getline; print $2}')"
24if [ "$SERVICE" = "$WIFI_DEV" ]; then ICON=$WIFI_4; TYPE="Wi-Fi"; else ICON=$ETHERNET; TYPE="Ethernet"; fi
25
26sketchybar --set "$NAME" label="$IP $ICON"
27
28# ---- popup details: interface, ip/cidr, gateway, SSID ----
29MASK="$(ifconfig "$SERVICE" 2>/dev/null | awk '/inet /{print $4; exit}')"
30CIDR=""
31if [ -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"
35fi
36GW="$(route -n get default 2>/dev/null | awk '/gateway:/{print $2}')"
37SSID=""
38if [ "$TYPE" = "Wi-Fi" ]; then
39 SSID="$(networksetup -getairportnetwork "$SERVICE" 2>/dev/null | sed -n 's/^Current Wi-Fi Network: //p')"
40fi
41
42LINE="$SERVICE · $TYPE · ${IP}${CIDR:+/$CIDR}"
43[ -n "$GW" ] && LINE="$LINE · gw $GW"
44[ -n "$SSID" ] && LINE="$LINE · $SSID"
45printf '%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.
4if [ "$SELECTED" = "true" ]; then
5 sketchybar --set "$NAME" icon.highlight=on
6else
7 sketchybar --set "$NAME" icon.highlight=off
8fi
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.
3source "$HOME/.config/sketchybar/icons.sh"
4
5# Waybar on-click: playerctl play-pause
6if [ "$1" = "toggle" ]; then
7 osascript -e 'tell application "Spotify" to playpause' 2>/dev/null
8 exit 0
9fi
10
11STATE="$(printf '%s' "$INFO" | sed -nE 's/.*"state":"([^"]*)".*/\1/p')"
12TITLE="$(printf '%s' "$INFO" | sed -nE 's/.*"title":"([^"]*)".*/\1/p')"
13ARTIST="$(printf '%s' "$INFO" | sed -nE 's/.*"artist":"([^"]*)".*/\1/p')"
14
15# exec-if check-for-music -> only draw while something is playing
16if [ "$STATE" = "playing" ] && [ -n "$TITLE" ]; then
17 sketchybar --set "$NAME" drawing=on label="$TITLE - $ARTIST"
18else
19 sketchybar --set "$NAME" drawing=off
20fi
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
2source "$CONFIG_DIR/colors.sh"
3source "$CONFIG_DIR/icons.sh"
4
5CACHE="/tmp/sketchybar_${NAME}.txt"
6case "$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 ;;
12esac
13
14# On APFS the real user usage lives on the Data volume; fall back to /
15VOL="/System/Volumes/Data"; [ -d "$VOL" ] || VOL="/"
16
17DF="$(df -h "$VOL" | awk 'NR==2{gsub("%","",$5); print $2, $3, $4, $5}')"
18set -- $DF; SIZE="$1"; USED="$2"; AVAIL="$3"; PCT="$4"
19[ -z "$PCT" ] && exit 0
20
21COLOR=$TEXT
22if [ "$PCT" -ge 90 ]; then COLOR=$RED # custom-storage.critical
23elif [ "$PCT" -ge 80 ]; then COLOR=$YELLOW # custom-storage.warning
24fi
25
26sketchybar --set "$NAME" label="${PCT}% ${DISK}" label.color=$COLOR
27printf '%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
2source "$CONFIG_DIR/colors.sh"
3source "$CONFIG_DIR/icons.sh"
4
5STEP=5 # % per scroll tick (Waybar used scroll-step: 1 — bump this down to taste)
6
7if [ "$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"
16elif [ "$SENDER" = "volume_change" ]; then
17 VOL="$INFO"
18else
19 VOL="$(osascript -e 'output volume of (get volume settings)')"
20fi
21
22MUTED="$(osascript -e 'output muted of (get volume settings)')"
23
24if [ "$MUTED" = "true" ] || { [ "$VOL" -eq 0 ] 2>/dev/null; }; then
25 sketchybar --set "$NAME" label="$VOL_MUTE" # format-muted
26 exit 0
27fi
28
29if [ "$VOL" -ge 66 ]; then ICON=$VOL_3
30elif [ "$VOL" -ge 33 ]; then ICON=$VOL_2
31elif [ "$VOL" -ge 1 ]; then ICON=$VOL_1
32else ICON=$VOL_0
33fi
34
35# Waybar: {volume} {icon}
36sketchybar --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.
4source "$CONFIG_DIR/colors.sh"
5source "$CONFIG_DIR/icons.sh"
6
7CACHE="/tmp/sketchybar_weather.txt"
8
9# --- hover: show/hide the popup, populated from the cached line ---
10case "$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 ;;
18esac
19
20command -v jq >/dev/null 2>&1 || { sketchybar --set "$NAME" label="wttr?"; exit 0; }
21
22JSON="$(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
26cc() { printf '%s' "$JSON" | jq -r ".current_condition[0].$1 // empty"; }
27CODE="$(cc weatherCode)"; TEMP="$(cc temp_F)"; FEELS="$(cc FeelsLikeF)"
28HUM="$(cc humidity)"; WSPD="$(cc windspeedMiles)"; WDIR="$(cc winddir16Point)"
29DESC="$(printf '%s' "$JSON" | jq -r '.current_condition[0].weatherDesc[0].value // empty')"
30AREA="$(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
33HOUR=$(date +%H); HOUR=${HOUR#0}; : "${HOUR:=0}"
34if [ "$HOUR" -ge 6 ] && [ "$HOUR" -lt 19 ]; then DAY=1; else DAY=0; fi
35
36# WWO weatherCode -> nf-weather glyph
37case "$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" ;;
48esac
49
50[ -z "$TEMP" ] && exit 0
51
52# bar: <icon> <temp>°F (drop " ${TEMP}°F" if you want the icon only)
53sketchybar --set "$NAME" label="$ICON ${TEMP}°F"
54
55# cache the single-line hover tooltip
56printf '%s' "${AREA:+$AREA · }${DESC} · feels ${FEELS}°F · ${HUM}% humidity · ${WDIR} ${WSPD}mph" > "$CACHE"
diff --git a/users/ryan/modules/sketchybar/bar-config/sketchybarrc b/users/ryan/modules/sketchybar/bar-config/sketchybarrc
new file mode 100755
index 0000000..446da25
--- /dev/null
+++ b/users/ryan/modules/sketchybar/bar-config/sketchybarrc
@@ -0,0 +1,172 @@
1#!/usr/bin/env bash
2# ============================================================================
3# sketchybarrc — translated from a Hyprland/Waybar config
4# Layout, fonts and colours mirror the original Waybar config + style.css.
5# ============================================================================
6CONFIG_DIR="$HOME/.config/sketchybar"
7PLUGIN_DIR="$CONFIG_DIR/plugins"
8source "$CONFIG_DIR/colors.sh"
9source "$CONFIG_DIR/icons.sh"
10
11env
12
13FONT="AnonymicePro Nerd Font"
14
15# ---- bar --------------------------------------------------------------------
16# From #waybar { background: rgba(0,0,0,0.25) } and Waybar height:30, position:top
17sketchybar --bar \
18 height=32 \
19 position=top \
20 color=$BAR_COLOR \
21 padding_left=8 \
22 padding_right=8 \
23 corner_radius=0 \
24 border_width=0 \
25 shadow=off
26
27# ---- defaults ---------------------------------------------------------------
28# From * { color:white; font: AnonymicePro Nerd Font 15px; no radius/shadow }
29sketchybar --default \
30 updates=when_shown \
31 icon.font="$FONT:Regular:15.0" \
32 icon.color=$TEXT \
33 icon.padding_left=4 \
34 icon.padding_right=4 \
35 label.font="$FONT:Regular:15.0" \
36 label.color=$TEXT \
37 label.padding_left=4 \
38 label.padding_right=4 \
39 background.corner_radius=0 \
40 background.height=32
41
42# ---- popup helper -----------------------------------------------------------
43# add_popup <item>: attaches a hover "tooltip" popup + a <item>.details child
44# (styled with POPUP_BG from window#waybar.solo) and subscribes to hover events.
45add_popup() {
46 sketchybar --set "$1" \
47 popup.background.color=$POPUP_BG \
48 popup.background.corner_radius=0 \
49 popup.background.border_width=0 \
50 popup.horizontal=off \
51 popup.y_offset=-1 \
52 --subscribe "$1" mouse.entered mouse.exited
53 sketchybar --add item "$1.details" "popup.$1" \
54 --set "$1.details" icon.drawing=off \
55 label.font="$FONT:Regular:13.0" \
56 label.padding_left=12 label.padding_right=12 \
57 background.height=24
58}
59
60# ============================================================================
61# LEFT — hyprland/workspaces -> yabai spaces
62# (hyprland/submap has no yabai/macOS analog -> omitted)
63# ============================================================================
64for sid in 1 2 3 4 5 6 7 8 9 10; do
65 sketchybar --add space space.$sid left \
66 --set space.$sid \
67 space=$sid \
68 icon=$sid \
69 icon.color=$TEXT_DIM \
70 icon.highlight_color=$TEXT \
71 label.drawing=off \
72 background.drawing=off \
73 padding_left=5 padding_right=5 \
74 script="$PLUGIN_DIR/space.sh" \
75 click_script="yabai -m space --focus $sid 2>/dev/null"
76done
77
78# ============================================================================
79# CENTER — hyprland/window -> front_app
80# ============================================================================
81sketchybar --add item front_app center \
82 --set front_app \
83 icon.drawing=off \
84 label.max_chars=80 \
85 label.padding_left=10 label.padding_right=10 \
86 script="$PLUGIN_DIR/front_app.sh" \
87 --subscribe front_app front_app_switched
88
89# ============================================================================
90# RIGHT — added right-to-left so the visual order matches Waybar's list:
91# spotify weather mail storage brightness bluetooth volume network
92# caffeinate battery clock
93# ============================================================================
94
95# clock (rightmost) — Waybar {:%a %d %b %H:%M}
96sketchybar --add item clock right \
97 --set clock update_freq=1 icon.drawing=off \
98 label.padding_left=10 label.padding_right=16 \
99 script="$PLUGIN_DIR/clock.sh"
100
101# battery (BAT0). Waybar battery#num2 (BAT1) omitted — Macs have one battery.
102sketchybar --add item battery right \
103 --set battery update_freq=60 icon.drawing=off \
104 script="$PLUGIN_DIR/battery.sh" \
105 --subscribe battery power_source_change system_woke
106add_popup battery
107
108# idle_inhibitor -> caffeinate
109sketchybar --add item caffeinate right \
110 --set caffeinate update_freq=15 \
111 script="$PLUGIN_DIR/caffeinate.sh" \
112 click_script="$PLUGIN_DIR/caffeinate.sh toggle"
113
114# network
115sketchybar --add item network right \
116 --set network update_freq=5 icon.drawing=off \
117 click_script="open -a 'System Settings' 2>/dev/null" \
118 script="$PLUGIN_DIR/network.sh"
119add_popup network
120
121# pulseaudio -> volume (native volume_change event)
122sketchybar --add item volume right \
123 --set volume icon.drawing=off script="$PLUGIN_DIR/volume.sh" \
124 --subscribe volume volume_change mouse.scrolled
125
126# bluetooth (needs blueutil)
127sketchybar --add item bluetooth right \
128 --set bluetooth update_freq=30 icon.drawing=off \
129 click_script="$PLUGIN_DIR/bluetooth.sh toggle" \
130 script="$PLUGIN_DIR/bluetooth.sh"
131add_popup bluetooth
132
133# backlight -> brightness (needs the `brightness` CLI; hides itself if absent)
134sketchybar --add item brightness right \
135 --set brightness update_freq=10 icon.drawing=off \
136 script="$PLUGIN_DIR/brightness.sh" \
137 --subscribe brightness mouse.scrolled
138
139# custom/storage
140sketchybar --add item storage right \
141 --set storage update_freq=60 icon.drawing=off \
142 script="$PLUGIN_DIR/storage.sh"
143add_popup storage
144
145# custom/mail (Mail.app unread)
146# sketchybar --add item mail right \
147# --set mail update_freq=60 icon.drawing=off \
148# click_script="open -a Mail" \
149# script="$PLUGIN_DIR/mail.sh"
150
151# custom/weather (wttr.in j2 -> condition icon + temp, hover popup as a "tooltip")
152sketchybar --add item weather right \
153 --set weather update_freq=1800 icon.drawing=off \
154 click_script="open https://wttr.in" \
155 script="$PLUGIN_DIR/weather.sh"
156add_popup weather
157
158# custom/spotify (now playing via native media_change)
159# sketchybar --add item spotify right \
160# --set spotify icon=$SPOTIFY icon.color=$TEXT drawing=off \
161# label.max_chars=30 scroll_texts=on \
162# click_script="$PLUGIN_DIR/spotify.sh toggle" \
163# script="$PLUGIN_DIR/spotify.sh" \
164# --subscribe spotify media_change
165
166# ----------------------------------------------------------------------------
167# Omitted (no SketchyBar / macOS analog):
168# tray -> the macOS menu bar already renders status/menu-extra items
169# privacy -> macOS shows camera/mic indicators natively in the menu bar
170# ----------------------------------------------------------------------------
171
172sketchybar --update
diff --git a/users/ryan/modules/sketchybar/default.nix b/users/ryan/modules/sketchybar/default.nix
new file mode 100644
index 0000000..8179f18
--- /dev/null
+++ b/users/ryan/modules/sketchybar/default.nix
@@ -0,0 +1,19 @@
1{ config, lib, pkgs, ... }:
2
3with lib;
4
5let
6 cfg = config.ryan.sketchybar;
7in
8{
9 options.ryan.sketchybar.enable = mkEnableOption "sketchybar";
10
11 config = mkIf cfg.enable {
12 # Enable the service
13 programs.sketchybar = {
14 enable = true;
15 extraPackages = [ pkgs.jq ];
16 config = { source = ./bar-config; recursive = true; };
17 };
18 };
19}