From 07e5e31722e067f48936942361aefbb9f06e8496 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matej=20Jane=C5=BEi=C4=8D?= Date: Fri, 13 Mar 2026 23:41:52 +0100 Subject: [PATCH] feat(waybar): drop eww and simplify components --- eww/eww.scss | 239 --------------- eww/eww.yuck | 421 -------------------------- eww/scripts/battery.sh | 44 --- eww/scripts/bluetooth.sh | 43 --- eww/scripts/keyboard.sh | 35 --- eww/scripts/media.sh | 46 --- eww/scripts/network.sh | 80 ----- eww/scripts/popup.sh | 29 -- eww/scripts/system.sh | 40 --- eww/scripts/volume.sh | 62 ---- eww/scripts/vpn.sh | 89 ------ sway/config.d/50-keybind.conf | 7 +- sway/config.d/80-autostart.conf | 3 +- swaync/config.json | 50 --- swaync/style.css | 163 ---------- waybar/config.jsonc | 59 +--- waybar/scripts/notification-status.sh | 14 - waybar/scripts/vpn-status.sh | 40 --- waybar/style.css | 22 +- 19 files changed, 20 insertions(+), 1466 deletions(-) delete mode 100644 eww/eww.scss delete mode 100644 eww/eww.yuck delete mode 100755 eww/scripts/battery.sh delete mode 100755 eww/scripts/bluetooth.sh delete mode 100755 eww/scripts/keyboard.sh delete mode 100755 eww/scripts/media.sh delete mode 100755 eww/scripts/network.sh delete mode 100755 eww/scripts/popup.sh delete mode 100755 eww/scripts/system.sh delete mode 100755 eww/scripts/volume.sh delete mode 100755 eww/scripts/vpn.sh delete mode 100644 swaync/config.json delete mode 100644 swaync/style.css delete mode 100755 waybar/scripts/notification-status.sh delete mode 100755 waybar/scripts/vpn-status.sh diff --git a/eww/eww.scss b/eww/eww.scss deleted file mode 100644 index 6ec71b5..0000000 --- a/eww/eww.scss +++ /dev/null @@ -1,239 +0,0 @@ -// gruvbox-material-soft-dark palette -$bg: #32302f; -$bg_dim: #252423; -$bg_sel: #45403d; -$fg: #d4be98; -$red: #ea6962; -$green: #a9b665; -$yellow: #d8a657; -$blue: #7daea3; -$magenta: #d3869b; -$cyan: #89b482; -$gray: #928374; - -// base -* { - all: unset; - font-family: "JetBrainsMono Nerd Font"; - font-size: 13px; -} - -// transparent backdrop for click-away dismiss -.backdrop { - background-color: transparent; -} - -// popup container -.popup { - background-color: $bg_dim; - border: 1px solid $bg_sel; - border-radius: 12px; - padding: 16px; -} - -// section titles -.title { - color: $fg; - font-size: 13px; - font-weight: bold; - margin-bottom: 4px; -} - -.subtitle { - color: $gray; - font-size: 12px; - margin-bottom: 2px; -} - -// labels and values -.label { - color: $gray; -} - -.value { - color: $fg; -} - -.value.dim { - color: $gray; - font-size: 12px; - margin-left: 8px; -} - -// detail lines (smaller, dimmer) -.details { - margin-top: 4px; - padding-top: 8px; - border-top: 1px solid $bg_sel; -} - -.detail { - color: $gray; - font-size: 12px; -} - -// rows -.row { - padding: 2px 0; -} - -// progress bars -progressbar { - border-radius: 3px; - - trough { - min-height: 4px; - border-radius: 3px; - background-color: $bg_sel; - - progress { - min-height: 4px; - border-radius: 3px; - background-color: $green; - } - } -} - -progressbar.warning trough progress { - background-color: $yellow; -} - -progressbar.critical trough progress { - background-color: $red; -} - -// sliders -scale { - margin: 0 4px; - - trough { - min-height: 4px; - border-radius: 3px; - background-color: $bg_sel; - - highlight { - min-height: 4px; - border-radius: 3px; - background-color: $blue; - } - - slider { - min-width: 14px; - min-height: 14px; - border-radius: 50%; - background-color: $fg; - margin: -5px 0; - } - } -} - -// buttons -.toggle-btn { - color: $gray; - padding: 2px 8px; - border-radius: 6px; - background-color: $bg_sel; - min-width: 30px; - - &.active { - color: $bg_dim; - background-color: $green; - } - - &:hover { - background-color: lighten($bg_sel, 10%); - } -} - -// device list buttons -.device-btn { - color: $fg; - padding: 6px 10px; - border-radius: 6px; - background-color: transparent; - - &.active { - background-color: $bg_sel; - color: $fg; - - label { - font-weight: bold; - } - } - - &:hover { - background-color: $bg; - } -} - -// device rows (non-clickable list items) -.device-row { - padding: 4px 10px; -} - -// close/disconnect button -.close-btn { - color: $gray; - padding: 2px 6px; - border-radius: 4px; - - &:hover { - color: $red; - background-color: $bg; - } -} - -// profile selector buttons -.profile-btn { - color: $gray; - padding: 6px 12px; - border-radius: 6px; - background-color: $bg; - - &.active { - color: $bg_dim; - background-color: $cyan; - font-weight: bold; - } - - &:hover { - background-color: $bg_sel; - } -} - -// separator line -.separator { - min-height: 1px; - background-color: $bg_sel; - margin: 4px 0; -} - -// status indicators -.indicator { - min-width: 14px; - - &.online { - color: $green; - } - - &.offline { - color: $gray; - } -} - -// empty state -.empty { - color: $gray; - font-size: 12px; - padding: 8px 0; -} - -// active player label -.playing { - color: $green; -} - -// slider row layout -.slider-row { - padding: 4px 0; -} diff --git a/eww/eww.yuck b/eww/eww.yuck deleted file mode 100644 index 3002585..0000000 --- a/eww/eww.yuck +++ /dev/null @@ -1,421 +0,0 @@ -; sway shell popups - -; ============================================================================= -; variables -; ============================================================================= - -(defpoll sys :interval "5s" - :initial '{"cpu":0,"ram_percent":0,"ram_used":"0Gi","ram_total":"0Gi","temp":0,"disk_percent":0,"disk_used":"0","disk_total":"0","swap":"0/0","load":"0 0 0","uptime":""}' - "~/.config/eww/scripts/system.sh") - -(defpoll bat :interval "30s" - :initial '{"capacity":0,"status":"Unknown","power":"0","time":"","cycles":0,"profile":"unknown"}' - "~/.config/eww/scripts/battery.sh") - -(defpoll vol :interval "5s" - :initial '{"volume":0,"muted":false,"mic_volume":0,"mic_muted":false,"brightness":0,"sinks":[],"sources":[],"sink_count":0,"source_count":0}' - "~/.config/eww/scripts/volume.sh") - -(defpoll bt :interval "15s" - :initial '{"powered":false,"count":0,"devices":[]}' - "~/.config/eww/scripts/bluetooth.sh") - -(defpoll net :interval "10s" - :initial '{"type":"none","iface":"none","ip":"none","gateway":"none","ssid":"","signal":0,"conn_name":"","count":0,"networks":[],"unknown_count":0,"unknown":[]}' - "~/.config/eww/scripts/network.sh") - -(defpoll vpn_data :interval "15s" - :initial '{"tailscale":{"running":false,"ip":"","hostname":"","login":"","exit_nodes":[],"exit_count":0,"peers":[],"peer_count":0},"wireguard":{"active":false,"iface":""}}' - "~/.config/eww/scripts/vpn.sh") - -(defpoll kbd :interval "10s" - :initial '{"current":"unknown","layouts":[],"layout_count":0,"keyboards":[],"kb_count":0}' - "~/.config/eww/scripts/keyboard.sh") - -(defpoll media :interval "5s" - :initial '{"count":0,"players":[]}' - "~/.config/eww/scripts/media.sh") - -; ============================================================================= -; media popup -; ============================================================================= - -(defwidget media-widget [] - (box :class "popup" :orientation "v" :space-evenly false :spacing 8 - (label :class "title" :text "media" :halign "start") - (box :visible {media.count == 0} - (label :class "empty" :text "no active players")) - (box :orientation "v" :space-evenly false :spacing 4 - (for player in {media.players} - (box :class "device-row" :orientation "v" :space-evenly false :spacing 2 - (box :orientation "h" :space-evenly false :spacing 8 - (label :class "label ${player.status == 'Playing' ? 'playing' : ''}" - :text {player.display} :halign "start" :hexpand true) - (button :class "toggle-btn ${player.status == 'Playing' ? 'active' : ''}" - :onclick "~/.config/eww/scripts/media.sh play-pause '${player.name}'" - {player.status == "Playing" ? "pause" : "play"}) - (button :class "close-btn" - :onclick "~/.config/eww/scripts/media.sh prev '${player.name}'" - "prev") - (button :class "close-btn" - :onclick "~/.config/eww/scripts/media.sh next '${player.name}'" - "next")) - (label :class "value" :text "${player.artist}${player.artist != '' ? ' - ' : ''}${player.title}" - :halign "start" :limit-width 45)))))) - -; ============================================================================= -; system popup -; ============================================================================= - -(defwidget system-widget [] - (box :class "popup" :orientation "v" :space-evenly false :spacing 8 - (label :class "title" :text "system" :halign "start") - - ; cpu - (box :class "row" :orientation "v" :space-evenly false :spacing 2 - (box :orientation "h" - (label :class "label" :text "cpu" :halign "start" :hexpand true) - (label :class "value" :text "${sys.cpu}%")) - (progress :class "bar" :value {sys.cpu})) - - ; ram - (box :class "row" :orientation "v" :space-evenly false :spacing 2 - (box :orientation "h" - (label :class "label" :text "ram" :halign "start" :hexpand true) - (label :class "value" :text "${sys.ram_used}/${sys.ram_total}")) - (progress :class "bar" :value {sys.ram_percent})) - - ; temp - (box :class "row" :orientation "h" - (label :class "label" :text "temp" :halign "start" :hexpand true) - (label :class "value" :text "${sys.temp}°")) - - ; disk - (box :class "row" :orientation "v" :space-evenly false :spacing 2 - (box :orientation "h" - (label :class "label" :text "disk" :halign "start" :hexpand true) - (label :class "value" :text "${sys.disk_used}/${sys.disk_total}")) - (progress :class "bar" :value {sys.disk_percent})) - - ; details - (box :class "details" :orientation "v" :space-evenly false :spacing 2 - (label :class "detail" :text "swap ${sys.swap}" :halign "start") - (label :class "detail" :text "load ${sys.load}" :halign "start") - (label :class "detail" :text "up ${sys.uptime}" :halign "start")))) - -; ============================================================================= -; battery popup -; ============================================================================= - -(defwidget battery-widget [] - (box :class "popup" :orientation "v" :space-evenly false :spacing 8 - (label :class "title" :text "battery" :halign "start") - - ; capacity bar - (box :class "row" :orientation "v" :space-evenly false :spacing 2 - (box :orientation "h" - (label :class "label" :text {bat.status} :halign "start" :hexpand true) - (label :class "value" :text "${bat.capacity}%")) - (progress :class "bar ${bat.capacity < 15 ? 'critical' : bat.capacity < 30 ? 'warning' : ''}" - :value {bat.capacity})) - - ; power + time - (box :class "row" :orientation "h" - (label :class "label" :text "power" :halign "start" :hexpand true) - (label :class "value" :text "${bat.power}W")) - (box :class "row" :orientation "h" :visible {bat.time != ""} - (label :class "label" :text "remaining" :halign "start" :hexpand true) - (label :class "value" :text {bat.time})) - (box :class "row" :orientation "h" - (label :class "label" :text "cycles" :halign "start" :hexpand true) - (label :class "value" :text {bat.cycles})) - - ; power profile selector - (box :class "separator") - (label :class "title" :text "profile" :halign "start") - (box :class "profiles" :orientation "h" :space-evenly true :spacing 4 - (button :class "profile-btn ${bat.profile == 'power-saver' ? 'active' : ''}" - :onclick "~/.config/eww/scripts/battery.sh set-profile power-saver" - "saver") - (button :class "profile-btn ${bat.profile == 'balanced' ? 'active' : ''}" - :onclick "~/.config/eww/scripts/battery.sh set-profile balanced" - "balanced") - (button :class "profile-btn ${bat.profile == 'performance' ? 'active' : ''}" - :onclick "~/.config/eww/scripts/battery.sh set-profile performance" - "perform")))) - -; ============================================================================= -; volume popup -; ============================================================================= - -(defwidget volume-widget [] - (box :class "popup" :orientation "v" :space-evenly false :spacing 8 - ; output section - (box :orientation "v" :space-evenly false :spacing 4 - (label :class "title" :text "output" :halign "start") - (box :class "row slider-row" :orientation "h" :space-evenly false :spacing 8 - (button :class "toggle-btn ${vol.muted ? 'active' : ''}" - :onclick "~/.config/eww/scripts/volume.sh toggle-mute" - {vol.muted ? "muted" : "vol"}) - (scale :class "slider" :min 0 :max 100 :value {vol.volume} - :onchange "pamixer --set-volume {}" :hexpand true) - (label :class "value" :text "${vol.volume}%")) - (for sink in {vol.sinks} - (button :class "device-btn ${sink.active ? 'active' : ''}" - :onclick "~/.config/eww/scripts/volume.sh set-sink '${sink.sink_name}'" - (label :text {sink.name} :halign "start")))) - - ; input section - (box :class "separator") - (box :orientation "v" :space-evenly false :spacing 4 - (label :class "title" :text "input" :halign "start") - (box :class "row slider-row" :orientation "h" :space-evenly false :spacing 8 - (button :class "toggle-btn ${vol.mic_muted ? 'active' : ''}" - :onclick "~/.config/eww/scripts/volume.sh toggle-mic" - {vol.mic_muted ? "muted" : "mic"}) - (scale :class "slider" :min 0 :max 100 :value {vol.mic_volume} - :onchange "pamixer --default-source --set-volume {}" :hexpand true) - (label :class "value" :text "${vol.mic_volume}%")) - (for source in {vol.sources} - (button :class "device-btn ${source.active ? 'active' : ''}" - :onclick "~/.config/eww/scripts/volume.sh set-source '${source.source_name}'" - (label :text {source.name} :halign "start")))) - - ; brightness section - (box :class "separator") - (label :class "title" :text "brightness" :halign "start") - (box :class "row slider-row" :orientation "h" :space-evenly false :spacing 8 - (label :class "label" :text "bl") - (scale :class "slider" :min 0 :max 100 :value {vol.brightness} - :onchange "brightnessctl set {}%" :hexpand true) - (label :class "value" :text "${vol.brightness}%")))) - -; ============================================================================= -; bluetooth popup -; ============================================================================= - -(defwidget bluetooth-widget [] - (box :class "popup" :orientation "v" :space-evenly false :spacing 8 - (box :class "row" :orientation "h" - (label :class "title" :text "bluetooth" :halign "start" :hexpand true) - (button :class "toggle-btn ${bt.powered ? 'active' : ''}" - :onclick "~/.config/eww/scripts/bluetooth.sh toggle-power" - {bt.powered ? "on" : "off"})) - - (box :visible {bt.powered} :orientation "v" :space-evenly false :spacing 4 - (for device in {bt.devices} - (box :class "device-row" :orientation "h" :space-evenly false :spacing 8 - (label :class "label" :text {device.name} :halign "start" :hexpand true) - (label :class "value dim" :visible {device.battery >= 0} - :text "${device.battery}%") - (button :class "close-btn" - :onclick "~/.config/eww/scripts/bluetooth.sh disconnect '${device.mac}'" - "x"))) - (label :visible {bt.count == 0} :class "empty" :text "no devices connected")))) - -; ============================================================================= -; network popup -; ============================================================================= - -(defwidget network-widget [] - (box :class "popup" :orientation "v" :space-evenly false :spacing 8 - (label :class "title" :text "network" :halign "start") - - ; connection info - (box :class "row" :orientation "h" - (label :class "label" :text "interface" :halign "start" :hexpand true) - (label :class "value" :text {net.iface})) - (box :class "row" :orientation "h" - (label :class "label" :text "ip" :halign "start" :hexpand true) - (label :class "value" :text {net.ip})) - (box :class "row" :orientation "h" - (label :class "label" :text "gateway" :halign "start" :hexpand true) - (label :class "value" :text {net.gateway})) - (box :class "row" :orientation "h" :visible {net.type == "wifi"} - (label :class "label" :text "ssid" :halign "start" :hexpand true) - (label :class "value" :text "${net.ssid} ${net.signal}%")) - - ; saved wifi networks nearby - (box :visible {net.count > 0} :orientation "v" :space-evenly false :spacing 4 - (box :class "separator") - (label :class "title" :text "saved" :halign "start") - (box :orientation "v" :space-evenly false :spacing 0 - (for network in {net.networks} - (button :class "device-btn ${network.active ? 'active' : ''}" - :onclick {network.active ? "~/.config/eww/scripts/network.sh disconnect '${network.ssid}'" : "~/.config/eww/scripts/network.sh connect '${network.ssid}'"} - (box :orientation "h" :space-evenly false - (label :class "label" :text {network.ssid} :halign "start" :hexpand true) - (label :class "value dim" :text "${network.signal}%")))))) - - ; unknown wifi networks nearby - (box :visible {net.unknown_count > 0} :orientation "v" :space-evenly false :spacing 4 - (box :class "separator") - (label :class "title" :text "nearby" :halign "start") - (box :orientation "v" :space-evenly false :spacing 0 - (for network in {net.unknown} - (button :class "device-btn" - :onclick "~/.config/eww/scripts/network.sh connect-new '${network.ssid}'" - (box :orientation "h" :space-evenly false - (label :class "label" :text {network.ssid} :halign "start" :hexpand true) - (label :class "value dim" :text "${network.signal}%")))))))) - -; ============================================================================= -; vpn popup -; ============================================================================= - -(defwidget vpn-widget [] - (box :class "popup" :orientation "v" :space-evenly false :spacing 8 - ; tailscale - (box :class "row" :orientation "h" - (label :class "title" :text "tailscale" :halign "start" :hexpand true) - (button :class "toggle-btn ${vpn_data.tailscale.running ? 'active' : ''}" - :onclick "~/.config/eww/scripts/vpn.sh ${vpn_data.tailscale.running ? 'ts-down' : 'ts-up'}" - {vpn_data.tailscale.running ? "on" : "off"})) - - (box :visible {vpn_data.tailscale.running} :orientation "v" :space-evenly false :spacing 4 - (box :class "row" :orientation "h" - (label :class "label" :text "ip" :halign "start" :hexpand true) - (label :class "value" :text {vpn_data.tailscale.ip})) - (box :class "row" :orientation "h" - (label :class "label" :text "host" :halign "start" :hexpand true) - (label :class "value" :text {vpn_data.tailscale.hostname})) - (box :class "row" :orientation "h" - (label :class "label" :text "network" :halign "start" :hexpand true) - (label :class "value" :text {vpn_data.tailscale.login})) - - ; exit nodes - (box :visible {vpn_data.tailscale.exit_count > 0} :orientation "v" :space-evenly false :spacing 4 - (box :class "separator") - (label :class "subtitle" :text "exit node" :halign "start") - (box :orientation "v" :space-evenly false :spacing 0 - (for node in {vpn_data.tailscale.exit_nodes} - (button :class "device-btn ${node.active ? 'active' : ''}" - :onclick "~/.config/eww/scripts/vpn.sh ts-exit '${node.active ? '' : node.ip}'" - (label :text {node.name} :halign "start"))))) - - ; peers - (box :orientation "v" :space-evenly false :spacing 4 - (box :class "separator") - (label :class "subtitle" :text "devices" :halign "start") - (for peer in {vpn_data.tailscale.peers} - (box :class "device-row" :orientation "h" :space-evenly false :spacing 8 - (label :class "indicator ${peer.online ? 'online' : 'offline'}" - :text {peer.online ? "●" : "○"}) - (label :class "label" :text {peer.name} :halign "start" :hexpand true) - (label :class "value dim" :text {peer.ip}))))) - - ; wireguard - (box :class "separator") - (box :class "row" :orientation "h" - (label :class "title" :text "wireguard" :halign "start" :hexpand true) - (button :class "toggle-btn ${vpn_data.wireguard.active ? 'active' : ''}" - :onclick "~/.config/eww/scripts/vpn.sh ${vpn_data.wireguard.active ? 'wg-down' : 'wg-up'}" - {vpn_data.wireguard.active ? "on" : "off"})))) - -; ============================================================================= -; keyboard popup -; ============================================================================= - -(defwidget keyboard-widget [] - (box :class "popup" :orientation "v" :space-evenly false :spacing 8 - (label :class "title" :text "keyboard" :halign "start") - - ; layout selector - (label :class "subtitle" :text "layout" :halign "start") - (for layout in {kbd.layouts} - (button :class "device-btn ${layout == kbd.current ? 'active' : ''}" - :onclick "~/.config/eww/scripts/keyboard.sh switch" - (label :text {layout} :halign "start"))) - - ; keyboard devices - (box :visible {kbd.kb_count > 1} :orientation "v" :space-evenly false :spacing 4 - (box :class "separator") - (label :class "subtitle" :text "devices" :halign "start") - (for kb in {kbd.keyboards} - (box :class "device-row" :orientation "h" :space-evenly false :spacing 8 - (label :class "label" :text {kb.name} :halign "start" :hexpand true) - (label :class "value dim" :text {kb.layout})))))) - -; ============================================================================= -; backdrop (click-away to close) -; ============================================================================= - -(defwidget backdrop-widget [] - (eventbox :onclick "~/.config/eww/scripts/popup.sh close-all" - (box :class "backdrop" :hexpand true :vexpand true))) - -(defwindow backdrop - :monitor 0 - :geometry (geometry :x "0px" :y "0px" :width "100%" :height "100%" :anchor "top left") - :stacking "overlay" - :exclusive false - :focusable true - (backdrop-widget)) - -; ============================================================================= -; windows -; ============================================================================= - -(defwindow system-popup - :monitor 0 - :geometry (geometry :x "380px" :y "3px" :width "300px" :anchor "top right") - :stacking "overlay" - :exclusive false - :focusable false - (system-widget)) - -(defwindow battery-popup - :monitor 0 - :geometry (geometry :x "260px" :y "3px" :width "300px" :anchor "top right") - :stacking "overlay" - :exclusive false - :focusable false - (battery-widget)) - -(defwindow volume-popup - :monitor 0 - :geometry (geometry :x "140px" :y "3px" :width "320px" :anchor "top right") - :stacking "overlay" - :exclusive false - :focusable false - (volume-widget)) - -(defwindow bluetooth-popup - :monitor 0 - :geometry (geometry :x "500px" :y "3px" :width "280px" :anchor "top right") - :stacking "overlay" - :exclusive false - :focusable false - (bluetooth-widget)) - -(defwindow network-popup - :monitor 0 - :geometry (geometry :x "560px" :y "3px" :width "320px" :anchor "top right") - :stacking "overlay" - :exclusive false - :focusable false - (network-widget)) - -(defwindow vpn-popup - :monitor 0 - :geometry (geometry :x "480px" :y "3px" :width "320px" :anchor "top right") - :stacking "overlay" - :exclusive false - :focusable false - (vpn-widget)) - -(defwindow keyboard-popup - :monitor 0 - :geometry (geometry :x "50px" :y "3px" :width "280px" :anchor "top right") - :stacking "overlay" - :exclusive false - :focusable false - (keyboard-widget)) - -(defwindow media-popup - :monitor 0 - :geometry (geometry :x "700px" :y "3px" :width "350px" :anchor "top right") - :stacking "overlay" - :exclusive false - :focusable false - (media-widget)) diff --git a/eww/scripts/battery.sh b/eww/scripts/battery.sh deleted file mode 100755 index e7889c3..0000000 --- a/eww/scripts/battery.sh +++ /dev/null @@ -1,44 +0,0 @@ -#!/usr/bin/env bash - -# battery info as JSON for eww battery-popup - -action="${1:-status}" - -if [[ "$action" == "set-profile" ]]; then - powerprofilesctl set "$2" - ( data=$(~/.config/eww/scripts/battery.sh); eww update bat="$data" ) & - exit 0 -fi - -bat_path=$(echo /sys/class/power_supply/BAT* 2>/dev/null | awk '{print $1}') - -if [[ ! -d "$bat_path" ]]; then - jq -nc '{capacity:0,status:"No battery",power:"0",time:"",cycles:0,profile:"unknown"}' - exit 0 -fi - -capacity=$(cat "$bat_path/capacity" 2>/dev/null || echo 0) -status=$(cat "$bat_path/status" 2>/dev/null || echo "Unknown") - -power_uw=$(cat "$bat_path/power_now" 2>/dev/null || echo 0) -power=$(awk -v p="$power_uw" 'BEGIN{printf "%.1f", p/1000000}') - -cycles=$(cat "$bat_path/cycle_count" 2>/dev/null || echo 0) -[[ "$cycles" =~ ^[0-9]+$ ]] || cycles=0 - -bat_upower=$(upower -e 2>/dev/null | grep BAT | head -1) -time_str="" -if [[ -n "$bat_upower" ]]; then - time_str=$(upower -i "$bat_upower" 2>/dev/null | awk '/time to/{print $4, $5}') -fi - -profile=$(powerprofilesctl get 2>/dev/null || echo "unknown") - -jq -nc \ - --argjson capacity "$capacity" \ - --arg status "$status" \ - --arg power "$power" \ - --arg time "$time_str" \ - --argjson cycles "${cycles:-0}" \ - --arg profile "$profile" \ - '{$capacity,$status,$power,$time,$cycles,$profile}' diff --git a/eww/scripts/bluetooth.sh b/eww/scripts/bluetooth.sh deleted file mode 100755 index 4b5c7bf..0000000 --- a/eww/scripts/bluetooth.sh +++ /dev/null @@ -1,43 +0,0 @@ -#!/usr/bin/env bash - -# bluetooth device info as JSON for eww bluetooth-popup - -action="${1:-status}" - -case "$action" in - status) - powered=$(bluetoothctl show 2>/dev/null | grep -q "Powered: yes" && echo true || echo false) - - devices="[]" - count=0 - if [[ "$powered" == "true" ]]; then - # get connected devices in one pass - devices=$(bluetoothctl devices Connected 2>/dev/null | while read -r _ mac name; do - info=$(bluetoothctl info "$mac" 2>/dev/null) - battery=$(awk '/Battery Percentage:/{gsub(/[()]/,""); print $4}' <<< "$info") - jq -nc --arg name "$name" --arg mac "$mac" --argjson battery "${battery:--1}" \ - '{$name,$mac,$battery}' - done | jq -sc '.') - [[ -z "$devices" || "$devices" == "null" ]] && devices="[]" - count=$(jq 'length' <<< "$devices" 2>/dev/null || echo 0) - fi - - jq -nc \ - --argjson powered "$powered" \ - --argjson count "$count" \ - --argjson devices "$devices" \ - '{$powered,$count,$devices}' - ;; - toggle-power) - if bluetoothctl show 2>/dev/null | grep -q "Powered: yes"; then - bluetoothctl power off - else - bluetoothctl power on - fi - ( sleep 0.5; data=$(~/.config/eww/scripts/bluetooth.sh); eww update bt="$data" ) & - ;; - disconnect) - bluetoothctl disconnect "$2" - ( sleep 0.5; data=$(~/.config/eww/scripts/bluetooth.sh); eww update bt="$data" ) & - ;; -esac diff --git a/eww/scripts/keyboard.sh b/eww/scripts/keyboard.sh deleted file mode 100755 index 9fd75de..0000000 --- a/eww/scripts/keyboard.sh +++ /dev/null @@ -1,35 +0,0 @@ -#!/usr/bin/env bash - -# keyboard layout info as JSON for eww keyboard-popup - -action="${1:-status}" - -case "$action" in - status) - inputs=$(swaymsg -t get_inputs 2>/dev/null) - - current=$(jq -r '[.[] | select(.type == "keyboard")] | .[0].xkb_active_layout_name // "unknown"' <<< "$inputs") - layouts=$(jq -c '[.[] | select(.type == "keyboard")] | .[0].xkb_layout_names // []' <<< "$inputs") - layout_count=$(jq 'length' <<< "$layouts" 2>/dev/null || echo 0) - - keyboards=$(jq -c '[.[] | select(.type == "keyboard") | - {id: .identifier, name: .name, layout: .xkb_active_layout_name}] | unique_by(.name)' <<< "$inputs") - kb_count=$(jq 'length' <<< "$keyboards" 2>/dev/null || echo 0) - - jq -nc \ - --arg current "${current:-unknown}" \ - --argjson layouts "${layouts:-[]}" \ - --argjson layout_count "${layout_count:-0}" \ - --argjson keyboards "${keyboards:-[]}" \ - --argjson kb_count "${kb_count:-0}" \ - '{$current,$layouts,$layout_count,$keyboards,$kb_count}' - ;; - switch) - swaymsg input type:keyboard xkb_switch_layout next 2>/dev/null - ( sleep 0.3; data=$(~/.config/eww/scripts/keyboard.sh); eww update kbd="$data" ) & - ;; - set-layout) - swaymsg input type:keyboard xkb_switch_layout "$2" 2>/dev/null - ( sleep 0.3; data=$(~/.config/eww/scripts/keyboard.sh); eww update kbd="$data" ) & - ;; -esac diff --git a/eww/scripts/media.sh b/eww/scripts/media.sh deleted file mode 100755 index 39c178a..0000000 --- a/eww/scripts/media.sh +++ /dev/null @@ -1,46 +0,0 @@ -#!/usr/bin/env bash - -# media player info as JSON for eww media-popup - -action="${1:-status}" - -case "$action" in - status) - players=$(playerctl -l 2>/dev/null | head -10) - if [[ -z "$players" ]]; then - jq -nc '{count:0,players:[]}' - exit 0 - fi - - result="[]" - while IFS= read -r name; do - status=$(playerctl -p "$name" status 2>/dev/null || echo "Stopped") - artist=$(playerctl -p "$name" metadata artist 2>/dev/null || echo "") - title=$(playerctl -p "$name" metadata title 2>/dev/null || echo "") - album=$(playerctl -p "$name" metadata album 2>/dev/null || echo "") - - # clean up player name for display - display=${name%%.*} - - result=$(jq -c --arg name "$name" --arg display "$display" \ - --arg status "$status" --arg artist "$artist" \ - --arg title "$title" --arg album "$album" \ - '. + [{name:$name, display:$display, status:$status, artist:$artist, title:$title, album:$album}]' <<< "$result") - done <<< "$players" - - count=$(jq 'length' <<< "$result") - jq -nc --argjson count "$count" --argjson players "$result" '{$count,$players}' - ;; - play-pause) - playerctl -p "$2" play-pause 2>/dev/null - ( sleep 0.3; data=$(~/.config/eww/scripts/media.sh); eww update media="$data" ) & - ;; - next) - playerctl -p "$2" next 2>/dev/null - ( sleep 0.5; data=$(~/.config/eww/scripts/media.sh); eww update media="$data" ) & - ;; - prev) - playerctl -p "$2" previous 2>/dev/null - ( sleep 0.5; data=$(~/.config/eww/scripts/media.sh); eww update media="$data" ) & - ;; -esac diff --git a/eww/scripts/network.sh b/eww/scripts/network.sh deleted file mode 100755 index c8aa3dd..0000000 --- a/eww/scripts/network.sh +++ /dev/null @@ -1,80 +0,0 @@ -#!/usr/bin/env bash - -# network info as JSON for eww network-popup - -action="${1:-status}" - -case "$action" in - status) - active=$(nmcli -t -f DEVICE,TYPE,STATE,CONNECTION device status 2>/dev/null \ - | grep ':connected:' | head -1) - iface=$(echo "$active" | cut -d: -f1) - conn_type=$(echo "$active" | cut -d: -f2) - conn_name=$(echo "$active" | cut -d: -f4-) - - ip=$(ip -4 -o addr show "$iface" 2>/dev/null | awk '{print $4}' | cut -d/ -f1) - gateway=$(ip route show default dev "$iface" 2>/dev/null | awk '{print $3}') - - networks="[]" - net_count=0 - - # always check active wifi regardless of primary connection type - ssid=$(nmcli -t -f active,ssid dev wifi 2>/dev/null | grep '^yes' | cut -d: -f2-) - signal=$(nmcli -t -f active,signal dev wifi 2>/dev/null | grep '^yes' | cut -d: -f2-) - signal=${signal:-0} - - # scan nearby wifi - saved=$(nmcli -t -f NAME connection show 2>/dev/null | sort -u) - # replace last 3 colons with tabs to handle SSIDs containing colons - all_wifi=$(nmcli -t -f SSID,SIGNAL,SECURITY,IN-USE dev wifi list --rescan no 2>/dev/null \ - | sed 's/:\([^:]*\):\([^:]*\):\([^:]*\)$/\t\1\t\2\t\3/' \ - | awk -F'\t' 'NF>=3 && $1!=""' \ - | sort -t$'\t' -k4,4r -k2,2rn \ - | awk -F'\t' '!seen[$1]++') - - # known networks nearby - networks=$(echo "$all_wifi" \ - | while IFS=$'\t' read -r s sig sec use; do - echo "$saved" | grep -qxF "$s" && printf '%s\t%s\n' "$s" "$sig" - done \ - | head -10 \ - | jq -Rnc --arg active "$ssid" '[inputs | split("\t") | - {ssid:.[0], signal:(.[1]|tonumber), active:(.[0] == $active)}]') - net_count=$(jq 'length' <<< "$networks" 2>/dev/null || echo 0) - - # unknown networks nearby - unknown=$(echo "$all_wifi" \ - | while IFS=$'\t' read -r s sig sec use; do - echo "$saved" | grep -qxF "$s" || printf '%s\t%s\t%s\n' "$s" "$sig" "$sec" - done \ - | head -5 \ - | jq -Rnc '[inputs | split("\t") | - {ssid:.[0], signal:(.[1]|tonumber), security:.[2]}]') - unknown_count=$(jq 'length' <<< "$unknown" 2>/dev/null || echo 0) - - jq -nc \ - --arg type "${conn_type:-none}" \ - --arg iface "${iface:-none}" \ - --arg ip "${ip:-none}" \ - --arg gateway "${gateway:-none}" \ - --arg ssid "$ssid" \ - --argjson signal "${signal:-0}" \ - --arg conn_name "$conn_name" \ - --argjson count "${net_count:-0}" \ - --argjson networks "${networks:-[]}" \ - --argjson unknown_count "${unknown_count:-0}" \ - --argjson unknown "${unknown:-[]}" \ - '{$type,$iface,$ip,$gateway,$ssid,$signal,$conn_name,$count,$networks,$unknown_count,$unknown}' - ;; - connect) - ( nmcli dev wifi connect "$2" 2>/dev/null; sleep 1; data=$(~/.config/eww/scripts/network.sh); eww update net="$data" ) & - ;; - disconnect) - ( nmcli connection down "$2" 2>/dev/null; sleep 1; data=$(~/.config/eww/scripts/network.sh); eww update net="$data" ) & - ;; - connect-new) - ssid="$2" - pass=$(zenity --entry --hide-text --title="WiFi" --text="Password for $ssid" 2>/dev/null) - ( [[ -n "$pass" ]] && nmcli dev wifi connect "$ssid" password "$pass" 2>/dev/null; sleep 1; data=$(~/.config/eww/scripts/network.sh); eww update net="$data" ) & - ;; -esac diff --git a/eww/scripts/popup.sh b/eww/scripts/popup.sh deleted file mode 100755 index 3f2271e..0000000 --- a/eww/scripts/popup.sh +++ /dev/null @@ -1,29 +0,0 @@ -#!/usr/bin/env bash - -# toggle an eww popup -# opens on the currently focused monitor - -POPUPS=(system-popup battery-popup network-popup vpn-popup volume-popup bluetooth-popup keyboard-popup media-popup) - -target="$1" - -if [[ -z "$target" ]]; then - echo "usage: popup.sh " >&2 - exit 1 -fi - -if [[ "$target" == "close-all" ]]; then - eww close "${POPUPS[@]}" 2>/dev/null - exit 0 -fi - -# check if target is already open -if eww active-windows 2>/dev/null | grep -q "$target"; then - eww close "$target" 2>/dev/null -else - # close others, open popup - screen=$(swaymsg -t get_outputs 2>/dev/null \ - | jq '[.[] | .focused] | index(true) // 0') - eww close "${POPUPS[@]}" 2>/dev/null - eww open --screen "${screen:-0}" "$target" -fi diff --git a/eww/scripts/system.sh b/eww/scripts/system.sh deleted file mode 100755 index 8fcd009..0000000 --- a/eww/scripts/system.sh +++ /dev/null @@ -1,40 +0,0 @@ -#!/usr/bin/env bash - -# system metrics as JSON for eww system-popup - -# delta-based cpu: sample /proc/stat twice 0.5s apart -read -r _ u1 n1 s1 i1 _ < /proc/stat -sleep 0.5 -read -r _ u2 n2 s2 i2 _ < /proc/stat -cpu=$(( (u2+n2+s2 - u1-n1-s1) * 100 / (u2+n2+s2+i2 - u1-n1-s1-i1) )) - -ram_info=$(free -b | awk '/^Mem:/{printf "%.0f %.1f %.1f", $3/$2*100, $3/1073741824, $2/1073741824}') -ram_percent=$(awk '{print $1}' <<< "$ram_info") -ram_used=$(awk '{printf "%.1f", $2}' <<< "$ram_info") -ram_total=$(awk '{printf "%.1f", $3}' <<< "$ram_info") - -temp=$(cat /sys/class/thermal/thermal_zone*/temp 2>/dev/null | sort -rn | head -1) -temp=$(( ${temp:-0} / 1000 )) - -disk_info=$(df -h / | awk 'NR==2{gsub(/%/,""); printf "%s %s %s", $5, $3, $2}') -disk_percent=$(awk '{print $1}' <<< "$disk_info") -disk_used=$(awk '{print $2}' <<< "$disk_info") -disk_total=$(awk '{print $3}' <<< "$disk_info") - -swap=$(free -h | awk '/^Swap:/{printf "%s/%s", $3, $2}') -load=$(awk '{print $1, $2, $3}' /proc/loadavg) -uptime_str=$(uptime -p 2>/dev/null | sed 's/up //' || echo "n/a") - -jq -nc \ - --argjson cpu "${cpu:-0}" \ - --argjson ram_percent "${ram_percent:-0}" \ - --arg ram_used "${ram_used:-0}Gi" \ - --arg ram_total "${ram_total:-0}Gi" \ - --argjson temp "${temp:-0}" \ - --argjson disk_percent "${disk_percent:-0}" \ - --arg disk_used "$disk_used" \ - --arg disk_total "$disk_total" \ - --arg swap "$swap" \ - --arg load "$load" \ - --arg uptime "$uptime_str" \ - '{$cpu,$ram_percent,$ram_used,$ram_total,$temp,$disk_percent,$disk_used,$disk_total,$swap,$load,$uptime}' diff --git a/eww/scripts/volume.sh b/eww/scripts/volume.sh deleted file mode 100755 index d966962..0000000 --- a/eww/scripts/volume.sh +++ /dev/null @@ -1,62 +0,0 @@ -#!/usr/bin/env bash - -# audio + brightness info for eww volume-popup - -action="${1:-status}" - -case "$action" in - status) - default_sink=$(pactl get-default-sink 2>/dev/null) - default_source=$(pactl get-default-source 2>/dev/null) - - # get all sink+source info in one pactl call, extract volume/mute + device lists - all_data=$(pactl --format=json list sinks 2>/dev/null) - sinks=$(jq -c --arg d "$default_sink" \ - '[.[] | {name: .description, sink_name: .name, active: (.name == $d)}]' <<< "$all_data" 2>/dev/null || echo '[]') - # extract default sink volume+mute - volume=$(jq --arg d "$default_sink" \ - '[.[] | select(.name == $d)][0] | .volume | to_entries[0].value.value_percent | rtrimstr("%") | tonumber' <<< "$all_data" 2>/dev/null || echo 0) - muted=$(jq --arg d "$default_sink" \ - '[.[] | select(.name == $d)][0].mute' <<< "$all_data" 2>/dev/null || echo false) - - all_sources=$(pactl --format=json list sources 2>/dev/null) - sources=$(jq -c --arg d "$default_source" \ - '[.[] | select(.name | test("monitor$") | not) | {name: .description, source_name: .name, active: (.name == $d)}]' <<< "$all_sources" 2>/dev/null || echo '[]') - mic_volume=$(jq --arg d "$default_source" \ - '[.[] | select(.name == $d)][0] | .volume | to_entries[0].value.value_percent | rtrimstr("%") | tonumber' <<< "$all_sources" 2>/dev/null || echo 0) - mic_muted=$(jq --arg d "$default_source" \ - '[.[] | select(.name == $d)][0].mute' <<< "$all_sources" 2>/dev/null || echo false) - - brightness=$(brightnessctl -m 2>/dev/null | cut -d, -f5 | tr -d '%') - sink_count=$(jq 'length' <<< "$sinks" 2>/dev/null || echo 0) - source_count=$(jq 'length' <<< "$sources" 2>/dev/null || echo 0) - - jq -nc \ - --argjson volume "${volume:-0}" \ - --argjson muted "${muted:-false}" \ - --argjson mic_volume "${mic_volume:-0}" \ - --argjson mic_muted "${mic_muted:-false}" \ - --argjson brightness "${brightness:-0}" \ - --argjson sinks "${sinks:-[]}" \ - --argjson sources "${sources:-[]}" \ - --argjson sink_count "${sink_count:-0}" \ - --argjson source_count "${source_count:-0}" \ - '{$volume,$muted,$mic_volume,$mic_muted,$brightness,$sinks,$sources,$sink_count,$source_count}' - ;; - set-sink) - pactl set-default-sink "$2" - ( data=$(~/.config/eww/scripts/volume.sh); eww update vol="$data" ) & - ;; - set-source) - pactl set-default-source "$2" - ( data=$(~/.config/eww/scripts/volume.sh); eww update vol="$data" ) & - ;; - toggle-mute) - pamixer -t - ( data=$(~/.config/eww/scripts/volume.sh); eww update vol="$data" ) & - ;; - toggle-mic) - pamixer --default-source -t - ( data=$(~/.config/eww/scripts/volume.sh); eww update vol="$data" ) & - ;; -esac diff --git a/eww/scripts/vpn.sh b/eww/scripts/vpn.sh deleted file mode 100755 index 4e8ed2d..0000000 --- a/eww/scripts/vpn.sh +++ /dev/null @@ -1,89 +0,0 @@ -#!/usr/bin/env bash - -# vpn status as JSON for eww vpn-popup - -action="${1:-status}" - -case "$action" in - status) - ts_running=false - ts_ip="" - ts_hostname="" - ts_login="" - ts_exit_nodes="[]" - ts_exit_count=0 - ts_peers="[]" - ts_peer_count=0 - - if command -v tailscale &>/dev/null; then - ts_json=$(tailscale status --json 2>/dev/null) - state=$(jq -r '.BackendState // empty' <<< "$ts_json") - - if [[ "$state" == "Running" ]]; then - ts_running=true - ts_ip=$(jq -r '.TailscaleIPs[0] // empty' <<< "$ts_json") - ts_hostname=$(jq -r '.Self.HostName // empty' <<< "$ts_json") - ts_login=$(jq -r '.CurrentTailnet.Name // empty' <<< "$ts_json") - - ts_exit_nodes=$(jq -c '[.Peer | to_entries[]? | - select(.value.ExitNodeOption) | - {id: .key, name: .value.HostName, ip: (.value.TailscaleIPs[0] // ""), active: (.value.ExitNode // false)} - ] // []' <<< "$ts_json" 2>/dev/null || echo '[]') - ts_exit_count=$(jq 'length' <<< "$ts_exit_nodes" 2>/dev/null || echo 0) - - ts_peers=$(jq -c '[.Peer | to_entries[]? | - {name: .value.HostName, ip: (.value.TailscaleIPs[0] // ""), online: .value.Online} - ] // []' <<< "$ts_json" 2>/dev/null || echo '[]') - ts_peer_count=$(jq 'length' <<< "$ts_peers" 2>/dev/null || echo 0) - fi - fi - - wg_active=false - wg_iface="" - if command -v wg &>/dev/null; then - wg_iface=$(wg show interfaces 2>/dev/null | head -1) - [[ -n "$wg_iface" ]] && wg_active=true - fi - - jq -nc \ - --argjson ts_running "$ts_running" \ - --arg ts_ip "$ts_ip" \ - --arg ts_hostname "$ts_hostname" \ - --arg ts_login "$ts_login" \ - --argjson ts_exit_nodes "$ts_exit_nodes" \ - --argjson ts_exit_count "$ts_exit_count" \ - --argjson ts_peers "$ts_peers" \ - --argjson ts_peer_count "$ts_peer_count" \ - --argjson wg_active "$wg_active" \ - --arg wg_iface "$wg_iface" \ - '{tailscale:{running:$ts_running,ip:$ts_ip,hostname:$ts_hostname,login:$ts_login, - exit_nodes:$ts_exit_nodes,exit_count:$ts_exit_count, - peers:$ts_peers,peer_count:$ts_peer_count}, - wireguard:{active:$wg_active,iface:$wg_iface}}' - ;; - ts-up) - tailscale up 2>/dev/null - ( sleep 1; data=$(~/.config/eww/scripts/vpn.sh); eww update vpn_data="$data" ) & - ;; - ts-down) - tailscale down 2>/dev/null - ( sleep 1; data=$(~/.config/eww/scripts/vpn.sh); eww update vpn_data="$data" ) & - ;; - ts-exit) - if [[ -n "$2" ]]; then - tailscale set --exit-node="$2" 2>/dev/null - else - tailscale set --exit-node="" 2>/dev/null - fi - ( sleep 0.5; data=$(~/.config/eww/scripts/vpn.sh); eww update vpn_data="$data" ) & - ;; - wg-up) - sudo wg-quick up "${2:-wg0}" 2>/dev/null - ( sleep 1; data=$(~/.config/eww/scripts/vpn.sh); eww update vpn_data="$data" ) & - ;; - wg-down) - iface="${2:-$(wg show interfaces 2>/dev/null | head -1)}" - sudo wg-quick down "${iface:-wg0}" 2>/dev/null - ( sleep 1; data=$(~/.config/eww/scripts/vpn.sh); eww update vpn_data="$data" ) & - ;; -esac diff --git a/sway/config.d/50-keybind.conf b/sway/config.d/50-keybind.conf index 892c84c..aabf542 100644 --- a/sway/config.d/50-keybind.conf +++ b/sway/config.d/50-keybind.conf @@ -11,15 +11,12 @@ bindsym $mod+Shift+Ctrl+Alt+space exec 1password --quick-access bindsym Print exec ~/.config/sway/scripts/screenshot.sh # notifications -bindsym $mod+n exec swaync-client -t -sw -bindsym $mod+Shift+n exec swaync-client -C -sw +bindsym $mod+n exec makoctl dismiss +bindsym $mod+Shift+n exec makoctl dismiss --all # clipboard bindsym $mod+c exec cliphist list | fuzzel -d | cliphist decode | wl-copy -# eww popups -bindsym $mod+Escape exec ~/.config/eww/scripts/popup.sh close-all - # window bindsym $mod+Shift+q kill diff --git a/sway/config.d/80-autostart.conf b/sway/config.d/80-autostart.conf index 739e2a9..ce0ed1b 100644 --- a/sway/config.d/80-autostart.conf +++ b/sway/config.d/80-autostart.conf @@ -1,9 +1,8 @@ # daemon -exec eww daemon +exec mako exec swayidle -w exec wlsunset -l 46.1 -L 14.5 exec pkill -x wob; rm -f $wobs && mkfifo $wobs && tail -f $wobs | wob -exec swaync exec wl-paste --watch cliphist store exec protonmail-bridge -n diff --git a/swaync/config.json b/swaync/config.json deleted file mode 100644 index b7c80c4..0000000 --- a/swaync/config.json +++ /dev/null @@ -1,50 +0,0 @@ -{ - "positionX": "right", - "positionY": "top", - "layer": "overlay", - "control-center-layer": "overlay", - "cssPriority": "application", - - "control-center-width": 400, - "control-center-height": 600, - "control-center-margin-top": 3, - "control-center-margin-right": 3, - "control-center-margin-bottom": 3, - - "notification-window-width": 400, - "notification-icon-size": 48, - "notification-body-image-height": 100, - "notification-body-image-width": 200, - - "timeout": 10, - "timeout-low": 5, - "timeout-critical": 0, - "transition-time": 200, - - "notification-grouping": true, - "image-visibility": "when-available", - "relative-timestamps": true, - "keyboard-shortcuts": true, - "hide-on-clear": true, - "hide-on-action": true, - "fit-to-screen": true, - - "widgets": [ - "title", - "dnd", - "notifications" - ], - "widget-config": { - "title": { - "text": "notifications", - "clear-all-button": true, - "button-text": "clear" - }, - "dnd": { - "text": "do not disturb" - }, - "notifications": { - "vexpand": true - } - } -} diff --git a/swaync/style.css b/swaync/style.css deleted file mode 100644 index 42c14e5..0000000 --- a/swaync/style.css +++ /dev/null @@ -1,163 +0,0 @@ -/* gruvbox-material-soft-dark */ -@define-color bg #32302f; -@define-color bg_dim #252423; -@define-color bg_sel #45403d; -@define-color fg #d4be98; -@define-color red #ea6962; -@define-color green #a9b665; -@define-color yellow #d8a657; -@define-color blue #7daea3; -@define-color magenta #d3869b; -@define-color cyan #89b482; -@define-color gray #928374; - -* { - font-family: "JetBrainsMono Nerd Font"; - font-size: 14px; - font-weight: bold; -} - -/* floating notifications */ -.floating-notifications { - background: transparent; -} - -.notification { - background-color: @bg; - border: 2px solid @bg_sel; - border-radius: 8px; - margin: 4px; - padding: 8px; -} - -.notification.critical { - border-color: @red; -} - -.notification .summary { - color: @fg; - font-size: 14px; -} - -.notification .body { - color: @gray; - font-size: 13px; -} - -.notification .time { - color: @gray; - font-size: 12px; -} - -.notification .image { - margin-right: 8px; - border-radius: 4px; -} - -.close-button { - background-color: @bg_sel; - color: @fg; - border-radius: 50%; - min-width: 24px; - min-height: 24px; - padding: 0; -} - -.close-button:hover { - background-color: @red; - color: @bg_dim; -} - -/* action buttons */ -.notification .text-button { - background-color: @bg_sel; - color: @fg; - border-radius: 4px; - padding: 4px 8px; - margin: 2px; -} - -.notification .text-button:hover { - background-color: @blue; - color: @bg_dim; -} - -/* control center panel */ -.control-center { - background-color: @bg_dim; - border: 2px solid @bg_sel; - border-radius: 8px; - padding: 8px; -} - -.control-center .notification-row { - background-color: transparent; - margin: 2px 0; -} - -.control-center .notification-row .notification { - background-color: @bg; - border: 1px solid @bg_sel; -} - -.control-center .notification-row:hover .notification { - border-color: @gray; -} - -/* title widget */ -.widget-title { - color: @fg; - padding: 4px 8px; -} - -.widget-title button { - background-color: @bg_sel; - color: @fg; - border-radius: 4px; - padding: 4px 12px; -} - -.widget-title button:hover { - background-color: @red; - color: @bg_dim; -} - -/* dnd toggle */ -.widget-dnd { - color: @fg; - padding: 4px 8px; -} - -.widget-dnd > switch { - background-color: @bg_sel; - border-radius: 12px; -} - -.widget-dnd > switch:checked { - background-color: @yellow; -} - -.widget-dnd > switch slider { - background-color: @fg; - border-radius: 50%; - min-width: 20px; - min-height: 20px; -} - -/* empty state */ -.widget-notifications > label { - color: @gray; - padding: 16px; -} - -/* notification group */ -.notification-group { - background-color: @bg; - border-radius: 8px; - margin: 4px; -} - -.notification-group .notification-group-headers { - padding: 4px 8px; - color: @gray; -} diff --git a/waybar/config.jsonc b/waybar/config.jsonc index 8ebb038..c45eed7 100644 --- a/waybar/config.jsonc +++ b/waybar/config.jsonc @@ -11,12 +11,10 @@ ], "modules-center": [ "custom/ssh", - "custom/notification", "systemd-failed-units" ], "modules-right": [ "mpris", - "custom/vpn", "cpu", "memory", "battery", @@ -25,7 +23,7 @@ "backlight", "sway/language", "bluetooth", - "network", + "custom/network", "clock" ], @@ -40,8 +38,7 @@ "sway/language": { "format": "{short}", - "on-click": "swaymsg input type:keyboard xkb_switch_layout next", - "on-click-right": "~/.config/eww/scripts/popup.sh keyboard-popup" + "on-click": "swaymsg input type:keyboard xkb_switch_layout next" }, "custom/ssh": { @@ -52,15 +49,6 @@ "on-click": "~/.config/waybar/scripts/ssh-session.sh disconnect" }, - "custom/notification": { - "format": "{}", - "return-type": "json", - "exec": "~/.config/waybar/scripts/notification-status.sh", - "on-click": "sleep 0.1 && swaync-client -t -sw", - "on-click-right": "sleep 0.1 && swaync-client -d -sw", - "escape": true - }, - "systemd-failed-units": { "hide-on-ok": true, "format": "!{nr_failed}", @@ -70,7 +58,6 @@ "on-click": "ghostty -e sh -c 'systemctl --failed; systemctl --user --failed; read'" }, - // right: media "mpris": { "format": "{artist} - {title}", "format-paused": "{artist} - {title} [paused]", @@ -78,53 +65,35 @@ "max-length": 35, "tooltip-format": "{player}: {artist} - {title} ({album})", "on-click": "playerctl play-pause", - "on-click-right": "~/.config/eww/scripts/popup.sh media-popup", "on-scroll-up": "playerctl next", "on-scroll-down": "playerctl previous" }, - // right: connectivity - "network": { + "custom/network": { + "format": "{}", + "return-type": "json", "interval": 5, - "format-ethernet": "󰈀 {ipaddr}", - "format-wifi": "󰖩 {ipaddr}", - "format-linked": "󰈀 (no ip)", - "format-disconnected": "󰖪", - "tooltip-format": "{ifname} {ipaddr}/{cidr}\n{gwaddr}\n{bandwidthUpBits}up {bandwidthDownBits}down", - "on-click-right": "~/.config/eww/scripts/popup.sh network-popup" + "exec": "~/.config/waybar/scripts/network-status.sh" }, "bluetooth": { "format": "󰂯", "format-connected": "󰂯 {num_connections}", "format-connected-battery": "󰂯 {num_connections}", - "tooltip-format-connected": "{device_enumerate}", - "on-click-right": "~/.config/eww/scripts/popup.sh bluetooth-popup" + "tooltip-format-connected": "{device_enumerate}" }, - "custom/vpn": { - "format": "{}", - "return-type": "json", - "interval": 10, - "exec": "~/.config/waybar/scripts/vpn-status.sh", - "on-click-right": "~/.config/eww/scripts/popup.sh vpn-popup" - }, - - "cpu": { "format": "󰻠 {usage}%", - "tooltip": false, - "on-click-right": "~/.config/eww/scripts/popup.sh system-popup" + "tooltip": false }, "memory": { "interval": 10, "format": "󰍛 {percentage}%", - "tooltip-format": "total: {total:0.2f}GiB\nused: {used:0.2f}GiB\navailable: {avail:0.2f}GiB\nswap: {swapUsed:0.2f}/{swapTotal:0.2f}GiB", - "on-click-right": "~/.config/eww/scripts/popup.sh system-popup" + "tooltip-format": "total: {total:0.2f}GiB\nused: {used:0.2f}GiB\navailable: {avail:0.2f}GiB\nswap: {swapUsed:0.2f}/{swapTotal:0.2f}GiB" }, - // right: battery "battery": { "states": { "warning": 30, @@ -136,16 +105,13 @@ "format-full": "󰁹 full", "format-alt": "{time}", "tooltip-format": "{timeTo}\n{power}W", - "on-click": "p=$(powerprofilesctl get); case $p in power-saver) n=balanced;; balanced) n=performance;; *) n=power-saver;; esac; powerprofilesctl set $n", - "on-click-right": "~/.config/eww/scripts/popup.sh battery-popup" + "on-click": "p=$(powerprofilesctl get); case $p in power-saver) n=balanced;; balanced) n=performance;; *) n=power-saver;; esac; powerprofilesctl set $n" }, - // right: audio "wireplumber": { "format": "󰕾 {volume}%", "format-muted": "󰖁 muted", "on-click": "pamixer -t", - "on-click-right": "~/.config/eww/scripts/popup.sh volume-popup", "on-scroll-up": "pamixer -i 5", "on-scroll-down": "pamixer -d 5", "tooltip-format": "{node_name}: {volume}%" @@ -157,18 +123,15 @@ "interval": 2, "exec": "~/.config/waybar/scripts/mic-status.sh", "on-click": "pamixer --default-source -t", - "on-click-right": "~/.config/eww/scripts/popup.sh volume-popup", "on-scroll-up": "pamixer --default-source -i 5", "on-scroll-down": "pamixer --default-source -d 5" }, "backlight": { "format": "󰃟 {percent}%", - "tooltip": false, - "on-click-right": "~/.config/eww/scripts/popup.sh volume-popup" + "tooltip": false }, - // right: clock "clock": { "interval": 1, "format": "{:%d/%m %H:%M:%S}", diff --git a/waybar/scripts/notification-status.sh b/waybar/scripts/notification-status.sh deleted file mode 100755 index 65e9a33..0000000 --- a/waybar/scripts/notification-status.sh +++ /dev/null @@ -1,14 +0,0 @@ -#!/usr/bin/env bash - -# wrap swaync subscription, hide when no notifications - -swaync-client -swb 2>/dev/null | while read -r line; do - count=$(echo "$line" | jq -r '.text // "0"') - class=$(echo "$line" | jq -r '.class // "none"') - - if [[ "$count" == "0" ]]; then - echo '{"text": "", "class": "none"}' - else - jq -nc --arg text "󰂚 $count" --arg class "$class" '{$text,$class}' - fi -done diff --git a/waybar/scripts/vpn-status.sh b/waybar/scripts/vpn-status.sh deleted file mode 100755 index 7d1c009..0000000 --- a/waybar/scripts/vpn-status.sh +++ /dev/null @@ -1,40 +0,0 @@ -#!/usr/bin/env bash - -# check wireguard and tailscale status -# outputs waybar JSON; empty when inactive - -parts=() -tooltip_parts=() - -if command -v wg &>/dev/null; then - ifaces=$(wg show interfaces 2>/dev/null) - if [[ -n "$ifaces" ]]; then - parts+=("󰖂") - tooltip_parts+=("wireguard: $ifaces") - fi -fi - -if command -v tailscale &>/dev/null; then - ts_json=$(tailscale status --json 2>/dev/null) - state=$(jq -r '.BackendState // empty' <<<"$ts_json") - if [[ "$state" == "Running" ]]; then - ts_ip=$(jq -r '.TailscaleIPs[0] // empty' <<<"$ts_json") - ts_name=$(jq -r '.Self.HostName // empty' <<<"$ts_json") - ts_exit=$(jq -r '.ExitNodeStatus.ID // empty' <<<"$ts_json") - parts+=("󰒒") - tip="tailscale: ${ts_name} ${ts_ip}" - if [[ -n "$ts_exit" ]]; then - tip="$tip (exit node)" - fi - tooltip_parts+=("$tip") - fi -fi - -if [[ ${#parts[@]} -gt 0 ]]; then - text="${parts[*]}" - tip=$(printf '%s\\n' "${tooltip_parts[@]}") - # strip trailing \n - tip=${tip%\\n} - jq -nc --arg text "$text" --arg tooltip "$tip" --arg class "active" \ - '{$text,$class,$tooltip}' -fi diff --git a/waybar/style.css b/waybar/style.css index 822dd1e..79a9b91 100644 --- a/waybar/style.css +++ b/waybar/style.css @@ -83,13 +83,12 @@ button:hover { #cpu, #memory, #backlight, -#network, #wireplumber, #mpris, #bluetooth, #language, #custom-mic, -#custom-vpn, +#custom-network, #custom-ssh, #custom-notification, #systemd-failed-units { @@ -101,17 +100,12 @@ button:hover { } /* center: alert zone */ -#custom-ssh { - min-height: 0; - padding-top: 0; - padding-bottom: 0; - margin-top: 3px; - margin-bottom: 3px; -} - #custom-ssh.active { color: @cyan; - font-size: 10px; + font-size: 18px; + padding: 0 10px; + margin-top: -2px; + margin-bottom: -2px; } #custom-notification.notification { @@ -153,7 +147,7 @@ button:hover { } /* right: connectivity */ -#network.disconnected { +#custom-network.disconnected { color: @red; } @@ -161,10 +155,6 @@ button:hover { color: @blue; } -#custom-vpn { - color: @cyan; -} - /* right: system */ #cpu { margin-right: 0;