diff --git a/home/home-darwin-work.nix b/home/home-darwin-work.nix index cd8c3b0..03fc633 100644 --- a/home/home-darwin-work.nix +++ b/home/home-darwin-work.nix @@ -107,6 +107,7 @@ aerospace = { enable = true; leader = "cmd"; + sketchybar.enable = true; # Optional: Add per-machine userSettings overrides # userSettings = { # mode.main.binding."${leader}-custom" = "custom-command"; diff --git a/home/roles/aerospace/default.nix b/home/roles/aerospace/default.nix index 985f8e9..4e0d728 100644 --- a/home/roles/aerospace/default.nix +++ b/home/roles/aerospace/default.nix @@ -61,6 +61,14 @@ in description = "Delay before focusing window"; }; }; + + sketchybar = { + enable = mkOption { + type = types.bool; + default = false; + description = "Whether to enable SketchyBar status bar"; + }; + }; }; config = mkIf cfg.enable { @@ -72,9 +80,19 @@ in } ]; - # Install aerospace package and autoraise if enabled + # Hide macOS menu bar when SketchyBar is enabled + # Note: Requires logout/login to take effect + targets.darwin.defaults = mkIf cfg.sketchybar.enable { + NSGlobalDomain = { + _HIHideMenuBar = true; + AppleMenuBarVisibleInFullscreen = false; + }; + }; + + # Install aerospace package and optional tools if enabled home.packages = [ pkgs.aerospace ] - ++ optionals cfg.autoraise.enable [ pkgs.autoraise ]; + ++ optionals cfg.autoraise.enable [ pkgs.autoraise ] + ++ optionals cfg.sketchybar.enable [ pkgs.sketchybar pkgs.sketchybar-app-font ]; # Enable and configure aerospace programs.aerospace.enable = true; @@ -185,7 +203,24 @@ in esc = "mode main"; "${cfg.leader}-p" = "mode main"; }; + + # SketchyBar integration - notify bar of workspace changes + exec-on-workspace-change = mkIf cfg.sketchybar.enable [ + "/bin/bash" "-c" + "${pkgs.sketchybar}/bin/sketchybar --trigger aerospace_workspace_change FOCUSED=$AEROSPACE_FOCUSED_WORKSPACE PREV=$AEROSPACE_PREV_WORKSPACE" + ]; } + # Gaps configuration - prevent windows from overlapping SketchyBar + (mkIf cfg.sketchybar.enable { + gaps = { + outer = { + top = 0; + bottom = 40; + left = 0; + right = 0; + }; + }; + }) cfg.userSettings ]; @@ -215,5 +250,396 @@ in KeepAlive = true; }; }; + + # SketchyBar configuration + home.file.".config/sketchybar/sketchybarrc" = mkIf cfg.sketchybar.enable { + executable = true; + onChange = "${pkgs.sketchybar}/bin/sketchybar --reload"; + text = '' + #!/bin/bash + + # Plugin directory + PLUGIN_DIR="$HOME/.config/sketchybar/plugins" + + # Colors - i3/sway theme with exact color matching + # Focused window/workspace color from i3/sway + FOCUSED=0xff285577 + + # Background colors matching i3blocks bar + BAR_BG=0xcc000000 # Semi-transparent black + ITEM_BG=0xff333333 # Dark gray for inactive items + + # Text colors + TEXT=0xffffffff # White text + GRAY=0xff888888 # Muted text for inactive items + + # Accent colors for warnings + WARNING=0xffff9900 + CRITICAL=0xff900000 + + # Configure the bar appearance + ${pkgs.sketchybar}/bin/sketchybar --bar \ + position=bottom \ + height=32 \ + color=$BAR_BG \ + border_width=0 \ + corner_radius=0 \ + padding_left=10 \ + padding_right=10 + + # Set default properties for all items + # Using monospace font to match waybar's Fira Code styling + ${pkgs.sketchybar}/bin/sketchybar --default \ + updates=when_shown \ + icon.font="SF Mono:Regular:13.0" \ + icon.color=$TEXT \ + icon.padding_left=4 \ + icon.padding_right=4 \ + label.font="SF Mono:Regular:13.0" \ + label.color=$TEXT \ + label.padding_left=4 \ + label.padding_right=4 \ + padding_left=4 \ + padding_right=4 \ + background.corner_radius=5 \ + background.height=24 + + # Register aerospace workspace change event + ${pkgs.sketchybar}/bin/sketchybar --add event aerospace_workspace_change + + # Create workspace indicators for workspaces 1-10 + for sid in 1 2 3 4 5 6 7 8 9 10; do + # Display "0" for workspace 10 + if [ "$sid" = "10" ]; then + display="0" + else + display="$sid" + fi + + ${pkgs.sketchybar}/bin/sketchybar --add item space.$sid left \ + --subscribe space.$sid aerospace_workspace_change \ + --set space.$sid \ + update_freq=2 \ + width=32 \ + background.color=$ITEM_BG \ + background.corner_radius=5 \ + background.height=20 \ + background.drawing=on \ + icon="$display" \ + icon.padding_left=13 \ + icon.padding_right=11 \ + icon.align=center \ + label.drawing=off \ + click_script="${pkgs.aerospace}/bin/aerospace workspace $sid" \ + script="$PLUGIN_DIR/aerospace.sh $sid" + done + + # Separator after workspaces + ${pkgs.sketchybar}/bin/sketchybar --add item separator_left left \ + --set separator_left \ + icon="" \ + label="" \ + background.drawing=off \ + padding_left=10 \ + padding_right=10 + + # System monitoring modules (right side) + # Note: Items added to 'right' appear in reverse order (last added = leftmost) + # Adding in reverse to get: disk | cpu | memory | battery | volume | calendar + ${pkgs.sketchybar}/bin/sketchybar --add item calendar right \ + --set calendar \ + icon="📅" \ + update_freq=30 \ + background.color=$ITEM_BG \ + background.drawing=on \ + script="$PLUGIN_DIR/calendar.sh" + + ${pkgs.sketchybar}/bin/sketchybar --add item separator_media right \ + --set separator_media \ + icon="|" \ + label="" \ + background.drawing=off \ + padding_left=5 \ + padding_right=5 + + ${pkgs.sketchybar}/bin/sketchybar --add item volume right \ + --set volume \ + background.color=$ITEM_BG \ + background.drawing=on \ + script="$PLUGIN_DIR/volume.sh" \ + --subscribe volume volume_change + + ${pkgs.sketchybar}/bin/sketchybar --add item battery right \ + --set battery \ + update_freq=120 \ + background.color=$ITEM_BG \ + background.drawing=on \ + script="$PLUGIN_DIR/battery.sh" \ + --subscribe battery system_woke power_source_change + + ${pkgs.sketchybar}/bin/sketchybar --add item separator_sys right \ + --set separator_sys \ + icon="|" \ + label="" \ + background.drawing=off \ + padding_left=5 \ + padding_right=5 + + ${pkgs.sketchybar}/bin/sketchybar --add item memory right \ + --set memory \ + update_freq=5 \ + icon="🐏" \ + background.color=$ITEM_BG \ + background.drawing=on \ + script="$PLUGIN_DIR/memory.sh" + + ${pkgs.sketchybar}/bin/sketchybar --add item cpu right \ + --set cpu \ + update_freq=2 \ + icon="🧠" \ + background.color=$ITEM_BG \ + background.drawing=on \ + script="$PLUGIN_DIR/cpu.sh" + + ${pkgs.sketchybar}/bin/sketchybar --add item disk right \ + --set disk \ + update_freq=60 \ + icon="💾" \ + background.color=$ITEM_BG \ + background.drawing=on \ + script="$PLUGIN_DIR/disk.sh" + + # Menu bar extras / system tray items (rightmost) + # Note: Requires Screen Recording permission for SketchyBar in System Settings + # Use 'sketchybar --query default_menu_items' to discover available items + + # Bluetooth + ${pkgs.sketchybar}/bin/sketchybar --add alias "Control Center,Bluetooth" right \ + --set "Control Center,Bluetooth" \ + alias.update_freq=1 \ + padding_left=0 \ + padding_right=0 + + # WiFi + ${pkgs.sketchybar}/bin/sketchybar --add alias "Control Center,WiFi" right \ + --set "Control Center,WiFi" \ + alias.update_freq=1 \ + padding_left=0 \ + padding_right=0 + + # Add other menu bar apps as discovered + # Common examples: + # - Cloudflare WARP: --add alias "Cloudflare WARP,Item-0" right + # - Notion Calendar: --add alias "Notion Calendar,Item-0" right + # Run 'sketchybar --query default_menu_items' to find exact names + + # Update the bar + ${pkgs.sketchybar}/bin/sketchybar --update + ''; + }; + + # SketchyBar aerospace workspace plugin + home.file.".config/sketchybar/plugins/aerospace.sh" = mkIf cfg.sketchybar.enable { + executable = true; + text = '' + #!/bin/bash + + # Colors + FOCUSED_COLOR=0xff285577 + ITEM_BG=0xff333333 + TEXT=0xffffffff + GRAY=0xff555555 + + # Get the currently focused workspace directly from aerospace + # Trim whitespace to ensure clean comparison + FOCUSED=$(${pkgs.aerospace}/bin/aerospace list-workspaces --focused | tr -d ' \n\r') + + # Get list of empty workspaces + EMPTY_WORKSPACES=$(${pkgs.aerospace}/bin/aerospace list-workspaces --monitor all --empty) + + # Clean up the workspace number parameter + WORKSPACE_NUM=$(echo "$1" | tr -d ' \n\r') + + # Check if workspace has windows (is NOT empty) + IS_EMPTY=false + if echo "$EMPTY_WORKSPACES" | grep -q "^$WORKSPACE_NUM$"; then + IS_EMPTY=true + fi + + # Check if this workspace is focused + IS_FOCUSED=false + if [ "$WORKSPACE_NUM" = "$FOCUSED" ]; then + IS_FOCUSED=true + fi + + # Determine visibility and styling + # Always show focused workspace (even if empty) with fixed width + # Hide non-focused empty workspaces by setting width to 0 (collapsed) + # Show non-focused non-empty workspaces with fixed width and inactive styling + + if [ "$IS_FOCUSED" = "true" ]; then + # Focused workspace - always show with focused styling + ${pkgs.sketchybar}/bin/sketchybar --set space.$WORKSPACE_NUM \ + drawing=on \ + width=32 \ + icon.padding_left=13 \ + icon.padding_right=11 \ + icon.align=center \ + background.color=$FOCUSED_COLOR \ + background.drawing=on \ + icon.color=$TEXT + elif [ "$IS_EMPTY" = "true" ]; then + # Empty workspace (not focused) - hide by turning off drawing + ${pkgs.sketchybar}/bin/sketchybar --set space.$WORKSPACE_NUM \ + drawing=off + else + # Non-empty workspace (not focused) - show with inactive styling + ${pkgs.sketchybar}/bin/sketchybar --set space.$WORKSPACE_NUM \ + drawing=on \ + width=32 \ + icon.padding_left=13 \ + icon.padding_right=11 \ + icon.align=center \ + background.color=$ITEM_BG \ + background.drawing=on \ + icon.color=$GRAY + fi + ''; + }; + + # SketchyBar CPU monitoring plugin + home.file.".config/sketchybar/plugins/cpu.sh" = mkIf cfg.sketchybar.enable { + executable = true; + text = '' + #!/bin/bash + + CORE_COUNT=$(sysctl -n machdep.cpu.thread_count) + CPU_INFO=$(ps -eo pcpu,user) + CPU_SYS=$(echo "$CPU_INFO" | grep -v $(whoami) | sed "s/[^ 0-9\.]//g" | awk "{sum+=\$1} END {print sum/(100.0 * $CORE_COUNT)}") + CPU_USER=$(echo "$CPU_INFO" | grep $(whoami) | sed "s/[^ 0-9\.]//g" | awk "{sum+=\$1} END {print sum/(100.0 * $CORE_COUNT)}") + CPU_PERCENT="$(echo "$CPU_SYS $CPU_USER" | awk '{printf "%.0f\n", ($1 + $2)*100}')" + + ${pkgs.sketchybar}/bin/sketchybar --set $NAME label="$CPU_PERCENT%" + ''; + }; + + # SketchyBar memory monitoring plugin + home.file.".config/sketchybar/plugins/memory.sh" = mkIf cfg.sketchybar.enable { + executable = true; + text = '' + #!/bin/bash + + MEMORY_STATS=$(vm_stat) + PAGES_FREE=$(echo "$MEMORY_STATS" | grep "Pages free" | awk '{print $3}' | tr -d '.') + PAGES_ACTIVE=$(echo "$MEMORY_STATS" | grep "Pages active" | awk '{print $3}' | tr -d '.') + PAGES_INACTIVE=$(echo "$MEMORY_STATS" | grep "Pages inactive" | awk '{print $3}' | tr -d '.') + PAGES_WIRED=$(echo "$MEMORY_STATS" | grep "Pages wired down" | awk '{print $4}' | tr -d '.') + PAGES_COMPRESSED=$(echo "$MEMORY_STATS" | grep "Pages stored in compressor" | awk '{print $5}' | tr -d '.') + + TOTAL_PAGES=$((PAGES_FREE + PAGES_ACTIVE + PAGES_INACTIVE + PAGES_WIRED + PAGES_COMPRESSED)) + USED_PAGES=$((PAGES_ACTIVE + PAGES_INACTIVE + PAGES_WIRED + PAGES_COMPRESSED)) + MEMORY_PERCENT=$((USED_PAGES * 100 / TOTAL_PAGES)) + + ${pkgs.sketchybar}/bin/sketchybar --set $NAME label="$MEMORY_PERCENT%" + ''; + }; + + # SketchyBar disk monitoring plugin + home.file.".config/sketchybar/plugins/disk.sh" = mkIf cfg.sketchybar.enable { + executable = true; + text = '' + #!/bin/bash + + DISK_USAGE=$(df -H / | grep -v Filesystem | awk '{print $5}') + + ${pkgs.sketchybar}/bin/sketchybar --set $NAME label="$DISK_USAGE" + ''; + }; + + # SketchyBar battery monitoring plugin + home.file.".config/sketchybar/plugins/battery.sh" = mkIf cfg.sketchybar.enable { + executable = true; + text = '' + #!/bin/bash + + PERCENTAGE=$(pmset -g batt | grep -Eo "\d+%" | cut -d% -f1) + CHARGING=$(pmset -g batt | grep 'AC Power') + + if [ "$PERCENTAGE" = "" ]; then + exit 0 + fi + + # Select icon based on battery level + case ''${PERCENTAGE} in + 9[0-9]|100) ICON="🔋" + ;; + [6-8][0-9]) ICON="🔋" + ;; + [3-5][0-9]) ICON="🔋" + ;; + [1-2][0-9]) ICON="🔋" + ;; + *) ICON="đŸĒĢ" + esac + + # Show charging icon if connected to power + if [[ $CHARGING != "" ]]; then + ICON="⚡" + fi + + ${pkgs.sketchybar}/bin/sketchybar --set $NAME icon="$ICON" label="''${PERCENTAGE}%" + ''; + }; + + # SketchyBar volume monitoring plugin + home.file.".config/sketchybar/plugins/volume.sh" = mkIf cfg.sketchybar.enable { + executable = true; + text = '' + #!/bin/bash + + if [ "$SENDER" = "volume_change" ]; then + VOLUME=$(osascript -e "output volume of (get volume settings)") + MUTED=$(osascript -e "output muted of (get volume settings)") + + if [ "$MUTED" = "true" ]; then + ICON="🔇" + LABEL="" + else + case $VOLUME in + [6-9][0-9]|100) ICON="🔊" + ;; + [3-5][0-9]) ICON="🔉" + ;; + *) ICON="🔈" + esac + LABEL="$VOLUME%" + fi + + ${pkgs.sketchybar}/bin/sketchybar --set $NAME icon="$ICON" label="$LABEL" + fi + ''; + }; + + # SketchyBar calendar/clock plugin + home.file.".config/sketchybar/plugins/calendar.sh" = mkIf cfg.sketchybar.enable { + executable = true; + text = '' + #!/bin/bash + + ${pkgs.sketchybar}/bin/sketchybar --set $NAME label="$(date '+%Y-%m-%d %H:%M')" + ''; + }; + + # Launchd agent for auto-starting sketchybar + launchd.agents.sketchybar = mkIf cfg.sketchybar.enable { + enable = true; + config = { + ProgramArguments = [ "${pkgs.sketchybar}/bin/sketchybar" ]; + RunAtLoad = true; + KeepAlive = true; + StandardOutPath = "/tmp/sketchybar.log"; + StandardErrorPath = "/tmp/sketchybar.err.log"; + }; + }; }; }