diff options
Diffstat (limited to 'arch/eww/.config')
| -rw-r--r-- | arch/eww/.config/eww/eww.scss | 112 | ||||
| -rw-r--r-- | arch/eww/.config/eww/eww.yuck | 150 | ||||
| -rwxr-xr-x | arch/eww/.config/eww/scripts/active-workspace | 4 | ||||
| -rwxr-xr-x | arch/eww/.config/eww/scripts/active-ws | 2 | ||||
| -rwxr-xr-x | arch/eww/.config/eww/scripts/cpu | 7 | ||||
| -rwxr-xr-x | arch/eww/.config/eww/scripts/hypr-socket | 24 | ||||
| -rwxr-xr-x | arch/eww/.config/eww/scripts/netspeed | 9 | ||||
| -rwxr-xr-x | arch/eww/.config/eww/scripts/powermenu | 7 | ||||
| -rwxr-xr-x | arch/eww/.config/eww/scripts/workspaces | 6 |
9 files changed, 321 insertions, 0 deletions
diff --git a/arch/eww/.config/eww/eww.scss b/arch/eww/.config/eww/eww.scss new file mode 100644 index 0000000..7fd3240 --- /dev/null +++ b/arch/eww/.config/eww/eww.scss @@ -0,0 +1,112 @@ +// Colors generated by wallust — see ~/.config/wallust/templates/eww-colors.scss +// Fallback values used until wallust has run at least once +$bg: #1e2121; +$fg: #cdd6f4; +$accent: #89b4fa; +$surface: #313244; +$muted: #6c7086; +$warn: #f38ba8; + +@import "/home/blake/.cache/wallust/eww-colors"; + +* { + font-family: "JetBrainsMono Nerd Font"; + font-size: 12px; + all: unset; +} + +.bar { + background-color: transparentize($bg, 0.4); + color: $fg; + border: none; + box-shadow: none; +} + +// ── Left ─────────────────────────────────────────────────────────────────── + +.left { + padding: 0 8px; +} + +.workspaces { + padding: 0 2px; +} + +.ws { + color: $muted; + padding: 0 5px; +} + +.ws.active { + color: $accent; + font-weight: bold; +} + +// ── Center ───────────────────────────────────────────────────────────────── + +.center { + padding: 0 8px; +} + +.date { + color: $muted; +} + +.clock { + color: $fg; + font-weight: bold; +} + +.music-icon { + color: $accent; +} + +.song { + color: $muted; +} + +// ── Right ────────────────────────────────────────────────────────────────── + +.right { + padding: 0 8px; +} + +.stat { + padding: 0 1px; +} + +.stat-label { + color: $muted; + padding-right: 3px; +} + +.stat-val { + color: $fg; +} + +.stat-val.net { + color: $muted; +} + +.stat-val.warn { + color: $warn; +} + +.stat-btn { + all: unset; +} + +.stat-btn:hover .stat-label, +.stat-btn:hover .stat-val { + color: $accent; +} + +.power-btn { + color: $muted; + padding: 0 4px; + margin-left: 2px; +} + +.power-btn:hover { + color: $warn; +} diff --git a/arch/eww/.config/eww/eww.yuck b/arch/eww/.config/eww/eww.yuck new file mode 100644 index 0000000..8574e1f --- /dev/null +++ b/arch/eww/.config/eww/eww.yuck @@ -0,0 +1,150 @@ +;; ── Listeners (Hyprland IPC) ────────────────────────────────────────────── +;; hyprland-workspaces emits JSON arrays with {id, name, windows, isActive} +;; on every workspace change — single source of truth for list + active state. + +(deflisten workspaces :initial "[]" + `scripts/workspaces`) + +;; ── Polls ────────────────────────────────────────────────────────────────── + +(defpoll clock :interval "1s" + `date +"%-H:%M"`) + +(defpoll date-str :interval "60s" + `date +"%a %b %d"`) + +;; Show the PLAYING source; fall back to any paused one +(defpoll player-status :interval "2s" + `playerctl -a status 2>/dev/null | grep -q "^Playing" && echo "Playing" || playerctl status 2>/dev/null || echo "Stopped"`) + +(defpoll player-song :interval "2s" + `playerctl -a metadata --format "{{status}}||{{ artist }} - {{ title }}" 2>/dev/null | grep "^Playing||" | head -1 | sed 's/^Playing||//' || playerctl metadata --format "{{ artist }} - {{ title }}" 2>/dev/null || echo ""`) + +(defpoll battery-level :interval "30s" :initial "100" + `cat /sys/class/power_supply/BAT0/capacity 2>/dev/null || echo "100"`) + +(defpoll battery-status :interval "10s" :initial "Unknown" + `cat /sys/class/power_supply/BAT0/status 2>/dev/null || echo "Unknown"`) + +(defpoll cpu :interval "3s" + `scripts/cpu`) + +(defpoll ram :interval "5s" + `free | awk '/^Mem/{printf "%d", $3/$2*100}'`) + +(defpoll disk :interval "60s" + `df / | awk 'NR==2{printf "%d", $3/$2*100}'`) + +(defpoll volume :interval "1s" + `pamixer --get-volume 2>/dev/null || echo "0"`) + +;; Use sysfs operstate — works regardless of network manager backend +(defpoll wifi-iface :interval "5s" + `IFACE=$(ls /sys/class/net | grep -m1 '^wl'); [ -n "$IFACE" ] && [ "$(cat /sys/class/net/$IFACE/operstate 2>/dev/null)" = "up" ] && echo "$IFACE" || echo "disconnected"`) + +(defpoll brightness :interval "2s" + `brightnessctl -m 2>/dev/null | awk -F, '{print int($4)}' || echo "100"`) + +(defpoll netspeed :interval "3s" + `scripts/netspeed`) + +;; ── Left: Workspaces + Music ─────────────────────────────────────────────── + +(defwidget workspaces [] + (box :class "workspaces" :space-evenly false :spacing 5 + (for ws in workspaces + (button + :class {ws.active ? "ws active" : "ws"} + :onclick "hyprctl dispatch workspace ${ws.id}" + {ws.id})))) + +(defwidget music [] + (eventbox + :onclick "playerctl play-pause" + (box :class "music" + :space-evenly false :spacing 5 + :visible {player-status != "Stopped" && player-status != ""} + (label :class "music-icon" + :text {player-status == "Playing" ? "▶" : "⏸"}) + (label :class "song" :text player-song :limit-width 30)))) + +;; ── Center: Clock ────────────────────────────────────────────────────────── + +(defwidget center-section [] + (box :class "center" :halign "center" :space-evenly false :spacing 8 + (label :class "date" :text date-str) + (label :class "clock" :text clock))) + +;; ── Right: Stats ─────────────────────────────────────────────────────────── + +(defwidget bright-stat [] + (eventbox + :onscroll "[ '{}' = 'up' ] && brightnessctl set +5% || brightnessctl set 5%-" + (box :class "stat" :space-evenly false :spacing 3 + (label :class "stat-label" :text "bright") + (label :class "stat-val" :text "${brightness}%")))) + +(defwidget audio-stat [] + (eventbox + :onscroll "[ '{}' = 'up' ] && pamixer --increase 5 || pamixer --decrease 5" + (box :class "stat" :space-evenly false :spacing 3 + (label :class "stat-label" :text "audio") + (label :class "stat-val" :text "${volume}%")))) + +(defwidget wifi-stat [] + (eventbox + :onclick "ghostty -e nmtui &" + (box :class "stat" :space-evenly false :spacing 3 + (label :class "stat-label" :text "wifi") + (label :class "stat-val" :text wifi-iface)))) + +(defwidget cpu-stat [] + (eventbox + :onclick "ghostty -e btop &" + (box :class "stat" :space-evenly false :spacing 3 + (label :class "stat-label" :text "cpu") + (label :class "stat-val" :text "${cpu}%")))) + +(defwidget right-section [] + (box :class "right" :halign "end" :space-evenly false :spacing 8 + (bright-stat) + (audio-stat) + (label :class "stat-val net" :text netspeed) + (wifi-stat) + (stat :lbl "bat" :value "${battery-level}%" + :class {battery-level < 20 ? "warn" : ""}) + (stat :lbl "strg" :value "${disk}%") + (stat :lbl "ram" :value "${ram}%") + (cpu-stat) + (button :class "power-btn" :onclick "scripts/powermenu &" "pwr"))) + +;; Plain stat (non-interactive) ───────────────────────────────────────────── + +(defwidget stat [lbl value ?class] + (box :class "stat" :space-evenly false :spacing 3 + (label :class "stat-label" :text lbl) + (label :class {class == "" ? "stat-val" : "stat-val ${class}"} :text value))) + +;; ── Bar ──────────────────────────────────────────────────────────────────── + +(defwidget bar [] + (centerbox :class "bar" :orientation "h" + (box :class "left" :halign "start" :space-evenly false :spacing 12 + (workspaces) + (music)) + (center-section) + (right-section))) + +(defwindow bar + :monitor 0 + :windowtype "dock" + :geometry (geometry + :x "0%" + :y "0%" + :width "100%" + :height "24px" + :anchor "top center") + :stacking "fg" + :exclusive true + :focusable false + (bar)) diff --git a/arch/eww/.config/eww/scripts/active-workspace b/arch/eww/.config/eww/scripts/active-workspace new file mode 100755 index 0000000..21795b9 --- /dev/null +++ b/arch/eww/.config/eww/scripts/active-workspace @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +hyprctl activeworkspace -j | jq '.id' +socat -u UNIX-CONNECT:"${XDG_RUNTIME_DIR}/hypr/${HYPRLAND_INSTANCE_SIGNATURE}/.socket2.sock" STDOUT \ + | while read -r _; do hyprctl activeworkspace -j | jq '.id'; done diff --git a/arch/eww/.config/eww/scripts/active-ws b/arch/eww/.config/eww/scripts/active-ws new file mode 100755 index 0000000..c7b3f3e --- /dev/null +++ b/arch/eww/.config/eww/scripts/active-ws @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +hyprctl activeworkspace | awk '/^workspace/{print $3}' diff --git a/arch/eww/.config/eww/scripts/cpu b/arch/eww/.config/eww/scripts/cpu new file mode 100755 index 0000000..f06ae7b --- /dev/null +++ b/arch/eww/.config/eww/scripts/cpu @@ -0,0 +1,7 @@ +#!/usr/bin/env bash +read -r _ u1 _ s1 id1 _ < /proc/stat +sleep 1 +read -r _ u2 _ s2 id2 _ < /proc/stat +used=$(( (u2+s2) - (u1+s1) )) +total=$(( (u2+s2+id2) - (u1+s1+id1) )) +printf "%d\n" $(( total > 0 ? 100 * used / total : 0 )) diff --git a/arch/eww/.config/eww/scripts/hypr-socket b/arch/eww/.config/eww/scripts/hypr-socket new file mode 100755 index 0000000..9012c17 --- /dev/null +++ b/arch/eww/.config/eww/scripts/hypr-socket @@ -0,0 +1,24 @@ +#!/usr/bin/env python3 +"""Stream lines from Hyprland's socket2 IPC.""" +import socket, sys, os + +sock_path = ( + os.environ.get("XDG_RUNTIME_DIR", f"/run/user/{os.getuid()}") + + "/hypr/" + + os.environ["HYPRLAND_INSTANCE_SIGNATURE"] + + "/.socket2.sock" +) + +s = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) +s.connect(sock_path) + +buf = b"" +while True: + chunk = s.recv(4096) + if not chunk: + break + buf += chunk + while b"\n" in buf: + line, buf = buf.split(b"\n", 1) + sys.stdout.write(line.decode(errors="replace") + "\n") + sys.stdout.flush() diff --git a/arch/eww/.config/eww/scripts/netspeed b/arch/eww/.config/eww/scripts/netspeed new file mode 100755 index 0000000..f5bb25b --- /dev/null +++ b/arch/eww/.config/eww/scripts/netspeed @@ -0,0 +1,9 @@ +#!/usr/bin/env bash +IFACE=$(ip route show default 2>/dev/null | awk '{print $5; exit}') +if [[ -z "$IFACE" ]]; then echo "↓0 ↑0 KB/s"; exit; fi +rx1=$(cat /sys/class/net/"$IFACE"/statistics/rx_bytes 2>/dev/null || echo 0) +tx1=$(cat /sys/class/net/"$IFACE"/statistics/tx_bytes 2>/dev/null || echo 0) +sleep 1 +rx2=$(cat /sys/class/net/"$IFACE"/statistics/rx_bytes 2>/dev/null || echo 0) +tx2=$(cat /sys/class/net/"$IFACE"/statistics/tx_bytes 2>/dev/null || echo 0) +echo "↓$(( (rx2-rx1)/1024 )) ↑$(( (tx2-tx1)/1024 )) KB/s" diff --git a/arch/eww/.config/eww/scripts/powermenu b/arch/eww/.config/eww/scripts/powermenu new file mode 100755 index 0000000..e136674 --- /dev/null +++ b/arch/eww/.config/eww/scripts/powermenu @@ -0,0 +1,7 @@ +#!/usr/bin/env bash +chosen=$(printf "Suspend\nReboot\nShutdown" | bemenu -p " Power") +case "$chosen" in + Suspend) systemctl suspend ;; + Reboot) systemctl reboot ;; + Shutdown) systemctl poweroff ;; +esac diff --git a/arch/eww/.config/eww/scripts/workspaces b/arch/eww/.config/eww/scripts/workspaces new file mode 100755 index 0000000..28571a7 --- /dev/null +++ b/arch/eww/.config/eww/scripts/workspaces @@ -0,0 +1,6 @@ +#!/usr/bin/env bash +# hyprland-workspaces streams JSON arrays on every workspace change. +# Filter out special/scratchpad workspaces (negative IDs). +hyprland-workspaces eDP-1 | while IFS= read -r line; do + echo "$line" | jq -c '[.[] | select(.id > 0)]' +done |