diff --git a/moduler/programs/waybar/default.nix b/moduler/programs/waybar/default.nix
index b986a7c..397ccb5 100644
--- a/moduler/programs/waybar/default.nix
+++ b/moduler/programs/waybar/default.nix
@@ -1,5 +1,5 @@
{
- lib,
+ lib,
config,
inputs,
pkgs,
@@ -27,16 +27,417 @@ with lib;
};
};
config = mkIf config.waybar.enable {
- programs = {
- waybar = {
- enable = true;
- systemd = {
- enable = true;
- };
- };
- };
- xdg.configFile."waybar/config.jsonc".source = config.waybar.configPath;
- xdg.configFile."waybar/style.css".source = config.waybar.stylePath;
+ programs = {
+ waybar = {
+ enable = true;
+ systemd = {
+ enable = true;
+ };
+ };
+ };
+ xdg.configFile."waybar/config.jsonc".source = config.waybar.configPath;
+ xdg.configFile."waybar/style.css".source = config.waybar.stylePath;
+ xdg.configFile."waybar/scripts/tailscale.sh" = {
+ text = ''
+ #!${pkgs.bash}/bin/bash
+
+ PATH=${
+ lib.makeBinPath [
+ pkgs.coreutils
+ pkgs.jq
+ pkgs.tailscale
+ ]
+ }
+
+ STATE_FILE="/tmp/waybar_tailscale_state"
+ CONNECTING_DURATION=2 # seconds to show transition states
+
+ get_tailscale_status() {
+ local status_json
+ if status_json=$(tailscale status --json 2>/dev/null); then
+ local backend_state=$(echo "$status_json" | jq -r '.BackendState // "NoState"')
+ case "$backend_state" in
+ "Running")
+ echo "connected"
+ ;;
+ "Stopped"|"NoState"|"NeedsLogin")
+ echo "stopped"
+ ;;
+ *)
+ echo "stopped"
+ ;;
+ esac
+ else
+ echo "stopped"
+ fi
+ }
+
+ get_tooltip() {
+ local status_json
+ if ! status_json=$(tailscale status --json 2>/dev/null); then
+ echo ""
+ return
+ fi
+
+ local backend_state=$(echo "$status_json" | jq -r '.BackendState // "NoState"')
+ if [[ "$backend_state" != "Running" ]]; then
+ echo ""
+ return
+ fi
+
+ local hostname=$(echo "$status_json" | jq -r '.Self.HostName // "Unknown"')
+
+ local tooltip="Hostname: $hostname\n"
+
+ tooltip+="\nPeers:\n"
+
+ local peers=$(echo "$status_json" | jq -r '.Peer // {} | to_entries[] | "\(.value.HostName):\(.value.Online)"' | sort)
+
+ if [[ -n "$peers" ]]; then
+ while IFS=: read -r peer_name peer_online; do
+ if [[ "$peer_online" == "true" ]]; then
+ tooltip+="\n● $peer_name"
+ else
+ tooltip+="\n● $peer_name"
+ fi
+ done <<< "$peers"
+ else
+ tooltip+="\nNo peers"
+ fi
+
+ echo "$tooltip"
+ }
+
+ show_status() {
+ local status=$(get_tailscale_status)
+ local text=""
+ local alt=""
+ local tooltip=""
+
+ case $status in
+ "connected")
+ text=""
+ alt="connected"
+ tooltip=$(get_tooltip)
+ ;;
+ "stopped")
+ text=""
+ alt="stopped"
+ tooltip="Tailscale is turned off"
+ ;;
+ esac
+
+ if [[ -n "$tooltip" ]]; then
+ echo "{\"text\":\"$text\",\"class\":\"$status\",\"alt\":\"$alt\",\"tooltip\":\"$tooltip\"}"
+ else
+ echo "{\"text\":\"$text\",\"class\":\"$status\",\"alt\":\"$alt\"}"
+ fi
+ }
+
+ show_connecting() {
+ echo "{\"text\":\"\",\"class\":\"connecting\",\"alt\":\"connecting\",\"tooltip\":\"Connecting...\"}"
+ }
+
+ show_disconnecting() {
+ echo "{\"text\":\"\",\"class\":\"disconnecting\",\"alt\":\"disconnecting\",\"tooltip\":\"Disconnecting...\"}"
+ }
+
+ is_in_transition() {
+ if [[ -f "$STATE_FILE" ]]; then
+ local state_info=$(cat "$STATE_FILE")
+ local state_time=$(echo "$state_info" | cut -d: -f1)
+ local current_time=$(date +%s)
+
+ if (( current_time - state_time < CONNECTING_DURATION )); then
+ return 0
+ else
+ rm -f "$STATE_FILE"
+ return 1
+ fi
+ fi
+ return 1
+ }
+
+ case "$1" in
+ --status)
+ if is_in_transition; then
+ state_info=$(cat "$STATE_FILE")
+ state_action=$(echo "$state_info" | cut -d: -f2)
+
+ if [[ "$state_action" == "connecting" ]]; then
+ show_connecting
+ exit 0
+ elif [[ "$state_action" == "disconnecting" ]]; then
+ show_disconnecting
+ exit 0
+ fi
+ fi
+
+ show_status
+ ;;
+ --toggle)
+ if is_in_transition; then
+ state_info=$(cat "$STATE_FILE")
+ state_action=$(echo "$state_info" | cut -d: -f2)
+
+ if [[ "$state_action" == "connecting" ]]; then
+ show_connecting
+ elif [[ "$state_action" == "disconnecting" ]]; then
+ show_disconnecting
+ fi
+ exit 0
+ fi
+
+ current_status=$(get_tailscale_status)
+ if [[ "$current_status" == "connected" ]]; then
+ tailscale down
+ show_status
+ else
+ echo "$(date +%s):connecting" > "$STATE_FILE"
+ tailscale up
+ show_connecting
+ fi
+ ;;
+ *)
+ echo "Usage: $0 {--status|--toggle}"
+ exit 1
+ ;;
+ esac
+ '';
+ executable = true;
+ };
+ xdg.configFile."waybar/scripts/netbird.sh" = {
+ text = ''
+ #!${pkgs.bash}/bin/bash
+
+ PATH=${
+ lib.makeBinPath [
+ pkgs.coreutils
+ pkgs.netbird
+ ]
+ }
+
+ STATE_FILE="/tmp/waybar_netbird_state"
+ CONNECTING_DURATION=2 # seconds to show transition states
+
+ get_netbird_status() {
+ local status_output
+ local management_status=""
+
+ if ! status_output=$(netbird status -d 2>/dev/null); then
+ echo "stopped"
+ return
+ fi
+
+ while IFS= read -r line; do
+ case "$line" in
+ "Management:"*)
+ management_status="''${line#Management: }"
+ ;;
+ esac
+ done <<< "$status_output"
+
+ case "$management_status" in
+ *Connected*)
+ echo "connected"
+ ;;
+ *)
+ echo "stopped"
+ ;;
+ esac
+ }
+
+ get_tooltip() {
+ local status_output
+ local management_status=""
+ local signal_status=""
+ local relays_available=0
+ local relays_total=0
+ local nameservers_available=0
+ local nameservers_total=0
+ local netbird_ip=""
+ local peers_count=""
+ local interface_type=""
+ local section=""
+
+ if ! status_output=$(netbird status -d 2>/dev/null); then
+ echo ""
+ return
+ fi
+
+ while IFS= read -r line; do
+ case "$line" in
+ "Management:"*)
+ management_status="''${line#Management: }"
+ section=""
+ ;;
+ "Signal:"*)
+ signal_status="''${line#Signal: }"
+ section=""
+ ;;
+ "Relays:"*)
+ section="relays"
+ ;;
+ "Nameservers:"*)
+ section="nameservers"
+ ;;
+ "NetBird IP:"*)
+ netbird_ip="''${line#NetBird IP: }"
+ section=""
+ ;;
+ "Interface type:"*)
+ interface_type="''${line#Interface type: }"
+ section=""
+ ;;
+ "Peers count:"*)
+ peers_count="''${line#Peers count: }"
+ section=""
+ ;;
+ "Peers detail:"*)
+ section=""
+ ;;
+ " ["*)
+ if [[ "$section" == "relays" ]]; then
+ relays_total=$((relays_total + 1))
+ if [[ "$line" == *"Available"* ]]; then
+ relays_available=$((relays_available + 1))
+ fi
+ elif [[ "$section" == "nameservers" ]]; then
+ nameservers_total=$((nameservers_total + 1))
+ if [[ "$line" == *"Available"* ]]; then
+ nameservers_available=$((nameservers_available + 1))
+ fi
+ fi
+ ;;
+ esac
+ done <<< "$status_output"
+
+ if [[ -z "$management_status" ]]; then
+ echo ""
+ return
+ fi
+
+ local tooltip="Management: $management_status"
+ if [[ -n "$signal_status" ]]; then
+ tooltip+="\nSignal: $signal_status"
+ fi
+ if (( relays_total > 0 )); then
+ tooltip+="\nRelays: $relays_available/$relays_total Available"
+ fi
+ if (( nameservers_total > 0 )); then
+ tooltip+="\nNameservers: $nameservers_available/$nameservers_total Available"
+ fi
+ if [[ -n "$netbird_ip" ]]; then
+ tooltip+="\nNetBird IP: $netbird_ip"
+ fi
+ if [[ -n "$interface_type" ]]; then
+ tooltip+="\nInterface: $interface_type"
+ fi
+ if [[ -n "$peers_count" ]]; then
+ tooltip+="\nPeers: $peers_count"
+ fi
+
+ echo "$tooltip"
+ }
+
+ show_status() {
+ local status=$(get_netbird_status)
+ local text=""
+ local alt=""
+ local tooltip=""
+
+ case $status in
+ "connected")
+ text=""
+ alt="connected"
+ tooltip=$(get_tooltip)
+ ;;
+ "stopped")
+ text=""
+ alt="stopped"
+ tooltip="NetBird is turned off"
+ ;;
+ esac
+
+ if [[ -n "$tooltip" ]]; then
+ echo "{\"text\":\"$text\",\"class\":\"$status\",\"alt\":\"$alt\",\"tooltip\":\"$tooltip\"}"
+ else
+ echo "{\"text\":\"$text\",\"class\":\"$status\",\"alt\":\"$alt\"}"
+ fi
+ }
+
+ show_connecting() {
+ echo "{\"text\":\"\",\"class\":\"connecting\",\"alt\":\"connecting\",\"tooltip\":\"Connecting...\"}"
+ }
+
+ show_disconnecting() {
+ echo "{\"text\":\"\",\"class\":\"disconnecting\",\"alt\":\"disconnecting\",\"tooltip\":\"Disconnecting...\"}"
+ }
+
+ is_in_transition() {
+ if [[ -f "$STATE_FILE" ]]; then
+ local state_info=$(cat "$STATE_FILE")
+ local state_time=$(echo "$state_info" | cut -d: -f1)
+ local current_time=$(date +%s)
+
+ if (( current_time - state_time < CONNECTING_DURATION )); then
+ return 0
+ else
+ rm -f "$STATE_FILE"
+ return 1
+ fi
+ fi
+ return 1
+ }
+
+ case "$1" in
+ --status)
+ if is_in_transition; then
+ state_info=$(cat "$STATE_FILE")
+ state_action=$(echo "$state_info" | cut -d: -f2)
+
+ if [[ "$state_action" == "connecting" ]]; then
+ show_connecting
+ exit 0
+ elif [[ "$state_action" == "disconnecting" ]]; then
+ show_disconnecting
+ exit 0
+ fi
+ fi
+
+ show_status
+ ;;
+ --toggle)
+ if is_in_transition; then
+ state_info=$(cat "$STATE_FILE")
+ state_action=$(echo "$state_info" | cut -d: -f2)
+
+ if [[ "$state_action" == "connecting" ]]; then
+ show_connecting
+ elif [[ "$state_action" == "disconnecting" ]]; then
+ show_disconnecting
+ fi
+ exit 0
+ fi
+
+ current_status=$(get_netbird_status)
+ if [[ "$current_status" == "connected" ]]; then
+ netbird down
+ show_status
+ else
+ echo "$(date +%s):connecting" > "$STATE_FILE"
+ netbird up
+ show_connecting
+ fi
+ ;;
+ *)
+ echo "Usage: $0 {--status|--toggle}"
+ exit 1
+ ;;
+ esac
+ '';
+ executable = true;
+ };
};
# catppuccin.waybar = {
# enable = true;
diff --git a/moduler/programs/waybar/waybar-laptop.jsonc b/moduler/programs/waybar/waybar-laptop.jsonc
index bcea439..f47b3f9 100644
--- a/moduler/programs/waybar/waybar-laptop.jsonc
+++ b/moduler/programs/waybar/waybar-laptop.jsonc
@@ -13,6 +13,8 @@
"bluetooth",
"pulseaudio",
"upower",
+ "custom/tailscale",
+ "custom/netbird",
"network",
"clock"
],
@@ -44,7 +46,7 @@
"on-click": "pgrep .blueman-manage && pkill .blueman-manage || blueman-manager &"
},
"network": {
- "interface": "wlp1s0",
+ "interface": "wlp0s20f3",
"format": "{ifname}",
"format-wifi": " {essid} ({signalStrength}%)",
"format-ethernet": "{ifname} ",
@@ -86,5 +88,35 @@
"tooltip": true,
"tooltip-format": "{:%A, %d %B %Y}\n %H:%M:%S",
"interval": 1
+ },
+ "custom/tailscale": {
+ "exec": "/home/fw/.config/waybar/scripts/tailscale.sh --status",
+ "on-click": "/home/fw/.config/waybar/scripts/tailscale.sh --toggle",
+ "exec-on-event": true,
+ "format": "{icon} {text}",
+ "format-icons": {
+ "connected": "",
+ "stopped": "",
+ "connecting": "",
+ "disconnecting": ""
+ },
+ "tooltip": true,
+ "return-type": "json",
+ "interval": 5
+ },
+ "custom/netbird": {
+ "exec": "/home/fw/.config/waybar/scripts/netbird.sh --status",
+ "on-click": "/home/fw/.config/waybar/scripts/netbird.sh --toggle",
+ "exec-on-event": true,
+ "format": "{icon} {text}",
+ "format-icons": {
+ "connected": "",
+ "stopped": "",
+ "connecting": "",
+ "disconnecting": ""
+ },
+ "tooltip": true,
+ "return-type": "json",
+ "interval": 5
}
}
diff --git a/moduler/programs/waybar/waybar-mocha.css b/moduler/programs/waybar/waybar-mocha.css
index 71edc44..c54b43c 100644
--- a/moduler/programs/waybar/waybar-mocha.css
+++ b/moduler/programs/waybar/waybar-mocha.css
@@ -19,6 +19,22 @@
font-size: 15px;
}
+.connecting {
+ animation: pulse 0.8s ease-in-out infinite;
+}
+
+@keyframes pulse {
+ 0% {
+ opacity: 1;
+ }
+ 50% {
+ opacity: 0.5;
+ }
+ 100% {
+ opacity: 1;
+ }
+}
+
window#waybar {
/* background: @base; */
background: transparent;
@@ -32,7 +48,7 @@ window#waybar.termite { background: @base; }
window#waybar.chromium { background: @base; border: none; }
/* -------- Module “pill” look -------- */
-#workspaces, #clock, #mpris, #pulseaudio, #bluetooth, #upower, #network {
+#workspaces, #clock, #mpris, #pulseaudio, #bluetooth, #upower, #network, #custom-tailscale, #custom-netbird {
background: @base;
border: none;
border-radius: 5px;
@@ -139,6 +155,22 @@ button:active {
letter-spacing: 0.2px;
}
+/* -------- Upower -------- */
+#custom-tailscale {
+ background: @peach;
+ color: @base;
+ font-weight: 600;
+ letter-spacing: 0.2px;
+}
+
+/* -------- Netbird -------- */
+#custom-netbird {
+ background: @peach;
+ color: @base;
+ font-weight: 600;
+ letter-spacing: 0.2px;
+}
+
/* -------- Network -------- */
#network {
background: @peach;
diff --git a/moduler/programs/waybar/waybar.jsonc b/moduler/programs/waybar/waybar.jsonc
index bb97f93..eca5509 100644
--- a/moduler/programs/waybar/waybar.jsonc
+++ b/moduler/programs/waybar/waybar.jsonc
@@ -12,6 +12,8 @@
"mpris",
"pulseaudio",
"bluetooth",
+ "custom/tailscale",
+ "custom/netbird",
"network",
"clock"
],
@@ -80,5 +82,35 @@
"tooltip": true,
"tooltip-format": "{:%A, %d %B %Y}\n %H:%M:%S",
"interval": 1
+ },
+ "custom/tailscale": {
+ "exec": "/home/fw/.config/waybar/scripts/tailscale.sh --status",
+ "on-click": "/home/fw/.config/waybar/scripts/tailscale.sh --toggle",
+ "exec-on-event": true,
+ "format": "{icon} {text}",
+ "format-icons": {
+ "connected": "",
+ "stopped": "",
+ "connecting": "",
+ "disconnecting": ""
+ },
+ "tooltip": true,
+ "return-type": "json",
+ "interval": 5
+ },
+ "custom/netbird": {
+ "exec": "/home/fw/.config/waybar/scripts/netbird.sh --status",
+ "on-click": "/home/fw/.config/waybar/scripts/netbird.sh --toggle",
+ "exec-on-event": true,
+ "format": "{icon} {text}",
+ "format-icons": {
+ "connected": "",
+ "stopped": "",
+ "connecting": "",
+ "disconnecting": ""
+ },
+ "tooltip": true,
+ "return-type": "json",
+ "interval": 5
}
}